-- CalcPaths.lua by Egaltech s.r.l. 2022/06/28 -- Calcolo percorsi di lavoro per Stampa 3d -- Tabella per definizione modulo local CalcPaths = {} -- Intestazioni require( 'EgtBase') EgtOutLog( ' CalcPaths started', 1) -- Dati local AMD = require( 'AddManData') --------------------------------------------------------------------- local s_nPartId local s_dOffsCorr = 10 * GEO.EPS_SMALL --------------------------------------------------------------------- local function GetLayerParamsForPathCalc() local LayerParams = {} LayerParams.bSpiralVase = EgtGetInfo( s_nPartId, KEY_SPIRAL_VASE, 'b') or false LayerParams.nShellsNbr = EgtGetInfo( s_nPartId, KEY_SHELLS_NBR, 'i') LayerParams.dStrand = EgtGetInfo( s_nPartId, KEY_STRAND, 'd') LayerParams.dLayHeight = EgtGetInfo( s_nPartId, KEY_SLICE_STEP, 'd') LayerParams.nStrandOverlap = EgtGetInfo( s_nPartId, KEY_STRAND_OVERLAP, 'i') or 0 LayerParams.dOffs = EgtGetInfo( s_nPartId, KEY_OFFSET_SLICE, 'd') LayerParams.nFloorNbr = EgtGetInfo( s_nPartId, KEY_FLOOR_NBR, 'i') or 0 LayerParams.nFloorType = EgtGetInfo( s_nPartId, KEY_FLOOR_TYPE, 'i') or INFILL_TYPE.ZIGZAG LayerParams.nCeilNbr = EgtGetInfo( s_nPartId, KEY_CEIL_NBR, 'i') or 0 LayerParams.nCeilType = EgtGetInfo( s_nPartId, KEY_CEIL_TYPE, 'i') or INFILL_TYPE.ZIGZAG LayerParams.vtSlicing = EgtGetInfo( s_nPartId, KEY_SLICING_DIR, 'v') LayerParams.bPrintInvert = ( EgtGetInfo( s_nPartId, KEY_PRINT_DIRECTION, 'i') == PRINT_DIRECTION.CW) LayerParams.vPrintOrder = EgtGetInfo( s_nPartId, KEY_PRINT_ORDER, 'vi') or { 1, 2, 3, 4, 5, 6, 7, 8} -- parametri costolature LayerParams.bRibsInvertOrder = EgtGetInfo( s_nPartId, KEY_RIBS_INVERT_ORDER, 'b') -- parametri regioni con diverse passate LayerParams.dShellNbrCoasting = EgtGetInfo( s_nPartId, KEY_SHELL_NBR_COASTING, 'd') LayerParams.dShellNbrWipe = EgtGetInfo( s_nPartId, KEY_SHELL_NBR_WIPE, 'd') LayerParams.dShellNbrWipeDir = EgtGetInfo( s_nPartId, KEY_SHELL_NBR_WIPE_DIR, 'd') -- eventuale modifica dei parametri per gestire correttamente il caso spiral vase if LayerParams.bSpiralVase then LayerParams.nShellsNbr = 1 LayerParams.nFloorNbr = 0 LayerParams.nCeilNbr = 0 end return LayerParams end -------------------------------------------------------------------------------------------- local function CopyInfo( nSouId, nDestId, sInfo, sType) local info = EgtGetInfo( nSouId, sInfo, sType) EgtSetInfo( nDestId, sInfo, info) end -------------------------------------------------------------------------------------------- local function UpdateInvertInfo( nId) local bInvert = EgtGetInfo( nId, KEY_INVERTED_CRV, 'b') or false EgtSetInfo( nId, KEY_INVERTED_CRV, not bInvert) end ---------------------------------------------------------------------- local function ComputeSurfOffset( nSrf, nGrpId, dOffs, vtSlicing) -- gruppo temporaneo locale local nGrpTmp = EgtGroup( nGrpId, Frame3d( ORIG(), vtSlicing), GDB_RT.GLOB) local nCopySrf = EgtCopyGlob( nSrf, nGrpTmp) or GDB_ID.NULL local bOk = EgtSurfFrOffset( nCopySrf, dOffs) local bExists = EgtSurfFrChunkCount( nCopySrf) > 0 if not bOk or not bExists then EgtErase( nCopySrf) nCopySrf = EgtCopyGlob( nSrf, nGrpTmp) or GDB_ID.NULL bOk = EgtSurfFrOffset( nCopySrf, dOffs + 0.05) bExists = EgtSurfFrChunkCount( nCopySrf) > 0 end EgtRelocateGlob( nCopySrf, nGrpId) EgtErase( nGrpTmp) return bOk, bExists, nCopySrf end --------------------------------------------------------------------- local function GetLayerStartPoint( nLayId, vtSlicing) -- recupero quota layer local dZ = EgtGetInfo( nLayId, KEY_SLICE_REAL_Z, 'd') local dDeltaZ = EgtGetInfo( nLayId, KEY_SLICE_DELTAZ, 'd') local frSlicing = Frame3d( ORIG(), vtSlicing) local ptOn = Point3d( 0, 0, dZ + dDeltaZ) ptOn:toGlob( frSlicing) -- gruppo temporaneo dove salvo i risultati local nGrpTmp = EgtGroup( nLayId) local vPtStart = {} local nMachStartGrp = EgtGetFirstNameInGroup( s_nPartId, LAY_MACH_START) local nStartId = EgtGetFirstInGroup( nMachStartGrp) while nStartId do local nType = EgtGetType( nStartId) -- se punto if nType == GDB_TY.GEO_POINT then table.insert( vPtStart, EgtSP( nStartId)) else -- se curva interseco con il piano local nId, nCnt = EgtPlaneCurveInters( ptOn, vtSlicing, nStartId, nGrpTmp, GDB_RT.GLOB) if nId then for i = nId, nId + nCnt - 1 do table.insert( vPtStart, EgtSP( i)) end end end nStartId = EgtGetNext( nStartId) end EgtErase( nGrpTmp) return vPtStart end --------------------------------------------------------------------- local function ModifyStartPoint( nCrvId, vPtStart) -- cerco lo start point più vicino tra quelli possibili if vPtStart and #vPtStart > 0 then local nMinIdx = -1 if #vPtStart == 1 then nMinIdx = 1 else local dMinDist = GEO.INFINITO for i = 1, #vPtStart do local dDist = EgtPointCurveDist( vPtStart[i], nCrvId) if dDist < dMinDist - 10 * GEO.EPS_SMALL then dMinDist = dDist nMinIdx = i end end end EgtChangeClosedCurveStartPoint( nCrvId, vPtStart[nMinIdx]) end end --------------------------------------------------------------------- local function GetPathsFromSurf( nSrfId, sName, nType, nGrpId, vPtStart) local vIds = {} local nChunks = EgtSurfFrChunkCount( nSrfId) for nC = 0, nChunks - 1 do -- estraggo i contorni local nCrvId, nCrvCnt = EgtExtractSurfFrChunkLoops( nSrfId, nC, nGrpId) for nInd = 0, nCrvCnt - 1 do EgtSetName( nCrvId + nInd, sName) EgtSetInfo( nCrvId + nInd, KEY_TYPE, nType) -- se è loop interno lo inverto per averlo orientato in senso antiorario if nInd > 0 then EgtInvertCurve( nCrvId + nInd) end -- verifico soddisfi i requisiti (lunghezza e area) local dLen = EgtCurveLength( nCrvId + nInd) local _ , _ , dArea = EgtCurveArea( nCrvId + nInd) if dLen < MIN_LEN or dArea < MIN_AREA then EgtErase( nCrvId + nInd) return end table.insert( vIds, nCrvId + nInd) ModifyStartPoint( nCrvId + nInd, vPtStart) end end return vIds end ---------------------------------------------------------------------- local function VerifyPath( nCrvId, dStrand, vtSlicing, nGrp) local _, _, dArea = EgtCurveArea( nCrvId) -- verifico se esiste l'offset (permetto una piccola sovrapposizione) local dAllowedOverlap = 1 local nRes, nCnt = EgtOffsetCurveAdv( nCrvId, - dStrand / 2 + dAllowedOverlap) -- se errore ritento con valore leggermente modificato if not nRes then nRes, nCnt = EgtOffsetCurveAdv( nCrvId, - dStrand / 2 + 0.05) if not nRes then return false end end for j = nRes, nRes + nCnt - 1 do EgtErase( j) end if nRes == GDB_ID.NULL or not dArea or dArea < GEO.EPS_SMALL then -- verifico se fattibile con una sola passata -- TODO da sistemare con medial axis per curva generica local bSingleStrand = false if EgtCurveIsClosed( nCrvId) then local nGrpTmp = EgtGroup( nGrp, Frame3d( ORIG(), vtSlicing), GDB_RT.GLOB) EgtRelocateGlob( nCrvId, nGrpTmp) local frLoc, dDimX, dDimY = EgtCurveMinAreaRectangleXY( nCrvId) if dDimY < 0.5 then -- TODO curva generica local dZ = EgtSP( nCrvId):getZ() -- creo la curva che corrisponde alla sigola passata local ptS = frLoc:getOrigin() - dDimX / 2 * frLoc:getVersX() + dZ * Z_AX() local ptE = frLoc:getOrigin() + dDimX / 2 * frLoc:getVersX() + dZ * Z_AX() if dist( ptS, ptE) > 5 then local nId = EgtCurveCompoFromPoints( nGrpTmp, { ptS, ptE}) local sName = EgtGetName( nCrvId) if sName then EgtSetName( nId, sName) end local nType = EgtGetInfo( nCrvId, KEY_TYPE, 'i') if nType then EgtSetInfo( nId, KEY_TYPE, nType) end EgtErase( nCrvId) EgtChangeId( nId, nCrvId) bSingleStrand = true end end EgtRelocateGlob( nCrvId, nGrp, GDB_IN.LAST_SON) EgtErase( nGrpTmp) end -- se non è fattibile con unica passata lo cancello if not bSingleStrand then EgtErase( nCrvId) return false end end return true end ------------------------------------------------------------------- local function ComputeTrimSurfWithOverlaps( vIds, nSrfBase, sKeyOverlap, dStrand, nGrp, vtSlicing) -- per ogni overlap creo le superfici con cui fare i trim local vSurfOffs = {} for i = 1, #vIds do local nOverlap = EgtGetInfo( vIds[i], sKeyOverlap, 'i') if not vSurfOffs[nOverlap] then local dNewOffs = nOverlap / 100 * dStrand local bOk, bExists, nSrfOffs = ComputeSurfOffset( nSrfBase, nGrp, dNewOffs, vtSlicing) if bOk then vSurfOffs[nOverlap] = nSrfOffs end end end return vSurfOffs end -------------------------------------------------------------------- --------------------- RIEMPIMENTI PIENI ---------------------------- -------------------------------------------------------------------- local function AdjustSurfForFloorCeil( nStrandDiff, nSrfTrim, nShellNbrSurfGrp) if EgtSurfFrChunkCount( nSrfTrim) == 0 then return end local nSurf = EgtCopyGlob( nSrfTrim, EgtGetParent( nSrfTrim)) if nShellNbrSurfGrp then local nIdx = nStrandDiff local nShellSurf = EgtGetFirstNameInGroup( nShellNbrSurfGrp, SHELL_NBR_SURF .. tostring( nIdx)) while nShellSurf do EgtSurfFrSubtract( nSurf, nShellSurf) nIdx = nIdx + 1 nShellSurf = EgtGetFirstNameInGroup( nShellNbrSurfGrp, SHELL_NBR_SURF .. tostring( nIdx)) end end return nSurf end -------------------------------------------------------------------- local function ReorderPath( vOldIds, vNewIds) if not vNewIds then return end if #vOldIds == 1 and #vNewIds == 1 then EgtRelocateGlob( vNewIds[1], vOldIds[1], GDB_IN.AFTER) return end -- associo ad ogni elemento di vOldIds gli elementi di vNewIds che contiene local vOrdered = {} if #vOldIds == 1 then vOrdered[vOldIds[1]] = vNewIds else local nGrp = EgtGetParent( vOldIds[1]) -- creo le superifici a partire dalle curve in vOldIds local vOldSurf = {} for i = 1, #vOldIds do local nSrf = EgtSurfFlatRegion( nGrp, {vOldIds[i]}) table.insert( vOldSurf, EgtIf( nSrf, nSrf, GDB_ID.NULL)) end for i = 1, #vNewIds do for j = 1, #vOldSurf do if vOldSurf[j] ~= GDB_ID.NULL then if not EgtSurfFrTestExternal( vOldSurf[j], vNewIds[i]) then if vOrdered[vOldIds[j]] then table.insert( vOrdered[vOldIds[j]], vNewIds[i]) else vOrdered[vOldIds[j]] = {vNewIds[i]} end break end end end end for i = 1, #vOldSurf do EgtErase( vOldSurf[i]) end end -- riordino for nParentIdx, vChildren in pairs( vOrdered) do if #vChildren == 1 then -- se racchiude solo una curva EgtRelocateGlob( vChildren[1], nParentIdx, GDB_IN.AFTER) else EgtSpInit() -- se racchiude più curve uso shortest path per ordinarle for j = 1, #vChildren do local pt = EgtGP( vChildren[j]) EgtSpAddPoint( pt:getX(), pt:getY(), pt:getZ(), 0, 0, pt:getX(), pt:getY(), pt:getZ(), 0, 0) end local ptS = EgtSP( nParentIdx) EgtSpSetOpenBound( true, SHP_OB.NEAR_PNT, ptS:getX(), ptS:getY(), ptS:getZ(), 0, 0) local vOrd, _ = EgtSpCalculate( SHP_TY.OPEN) EgtSpTerminate() for j = #vOrd, 1, -1 do EgtRelocateGlob( vChildren[vOrd[j]], nParentIdx, GDB_IN.AFTER) end end end end --------------------------------------------------------------------------- local function ComputeOffsetInfill( nSrf, dStrand, vtSlicing, sName, nType, vPtStart, nGrp) local nChunk = EgtSurfFrChunkCount( nSrf) if nChunk == 0 then return end -- estraggo i contorni della superficie local vOldIds = GetPathsFromSurf( nSrf, sName, nType, nGrp, vPtStart) local dOffs = - dStrand local bOk, bExists, nSrfOffs = ComputeSurfOffset( nSrf, nGrp, dOffs, vtSlicing) while bOk and bExists do -- estraggo i contorni local vNewIds = GetPathsFromSurf( nSrfOffs, sName, nType, nGrp, vPtStart) if vNewIds then -- riordino ReorderPath( vOldIds, vNewIds) -- verifico fattibilità local k = 1 while k <= #vNewIds do if VerifyPath( vNewIds[k], dStrand, vtSlicing, nGrp) then k = k + 1 else -- se non è fattibile lo rimuovo dalla table per non ritrovarlo nello step successivo table.remove( vNewIds, k) end end vOldIds = vNewIds end EgtErase( nSrfOffs) -- offset successivo dOffs = dOffs - dStrand bOk, bExists, nSrfOffs = ComputeSurfOffset( nSrf, nGrp, dOffs, vtSlicing) end end -------------------------------------------------------------------------------- local function ComputeZigZagInfill( nSrf, dStrand, vtSlicing, sName, nType, vPtStart, nGrp) local nChunk = EgtSurfFrChunkCount( nSrf) if nChunk == 0 then return end local nCopySrf = EgtCopyGlob( nSrf, nGrp) if EgtSurfFrChunkCount( nSrf) == 0 then return end local nFirst, nCnt = EgtExplodeSurf( nCopySrf) local frLoc = Frame3d( ORIG(), vtSlicing) local vIds = {} for nId = nFirst, nFirst + nCnt - 1 do local nGrpTmp = EgtGroup( nGrp, frLoc, GDB_RT.GLOB) -- recupero outer curve local nCrvGrpId = EgtGetParent( nGrp) local nOuterCrv = EgtGetFirstNameInGroup( nCrvGrpId, OUTER_CRV) local nCopyOuterCrv = EgtCopyGlob( nOuterCrv, nGrpTmp) -- cerco il lato più lungo local vCrvIds = GetPathsFromSurf( nId, 'Tmp', nType, nGrpTmp) local dMaxLen = - GEO.INFINITO local dDist = GEO.INFINITO local vtDir for j = 1, #vCrvIds do local nId, nCnt = EgtExplodeCurveCompo( vCrvIds[j]) -- cerco il lato più lungo for k = nId, nId + nCnt - 1 do local dCurrLen = EgtCurveLength( k) if dCurrLen > dMaxLen + GEO.EPS_SMALL then dMaxLen = dCurrLen end end -- tra i lati più lunghi scelgo quello più vicino al bordo for k = nId, nId + nCnt - 1 do local dCurrLen = EgtCurveLength( k) if abs( dMaxLen - dCurrLen) < 10 then local dCurrDist = EgtPointCurveDist( EgtMP( k), nCopyOuterCrv) if dCurrDist < dDist + 10 * GEO.EPS_SMALL then vtDir = EgtSV( k) dDist = dCurrDist end end end end EgtErase( nGrpTmp) local _, _, dAng = SphericalFromVector( vtDir) vtDir:toGlob( frLoc) local nInd, nCnt = EgtGetSurfFrZigZagInfill( nId, nGrp, dStrand, dAng, false, false) if not nInd then return end for j = nInd, nInd + nCnt - 1 do EgtSetName( j, sName) EgtSetInfo( j, KEY_TYPE, nType) EgtSetInfo( j, KEY_ZIG_ZAG_DIR, vtDir) EgtSetInfo( j, KEY_ZIG_ZAG_INFILL, 1) EgtModifyCurveExtrusion( j, vtSlicing, GDB_RT.GLOB) table.insert( vIds, j) end local vtS = EgtSV( nInd) EgtErase( nId) end end -------------------------------------------------------------------- --------------------------- RIBS ----------------------------------- -------------------------------------------------------------------- local function VerifyRibsHoles( vIds, dStrand) local sPrevName = EgtGetName( vIds[1]) local i = 2 while i <= #vIds do local bAdd = false local sCurrName = EgtGetName( vIds[i]) -- se derivano dallo stesso setto verifico se possono essere uniti if sCurrName == sPrevName then if dist( EgtEP( vIds[i-1]), EgtSP( vIds[i])) < dStrand + 10 * GEO.EPS_SMALL then bAdd = true -- unisco il secondo tratto al primo EgtAddCurveCompoLine( vIds[i-1], EgtSP( vIds[i])) EgtAddCurveCompoCurve( vIds[i-1], vIds[i]) table.remove( vIds, i) -- rimuovo il setto dalla tabella elseif dist( EgtSP( vIds[i-1]), EgtEP( vIds[i])) < dStrand + 10 * GEO.EPS_SMALL then bAdd = true -- unisco il primo tratto al secondo EgtAddCurveCompoLine( vIds[i], EgtSP( vIds[i-1])) EgtAddCurveCompoCurve( vIds[i], vIds[i-1]) table.remove( vIds, i-1) -- rimuovo il setto dalla tabella end end -- aggiorno per iterazione successiva sPrevName = sCurrName if not bAdd then i = i + 1 end end end -------------------------------------------------------------------- local function CheckRibUserLink( nCrv, nCnt, vtSlicing) -- se dal trim non ho ottenuto almeno due tratti, non si tratta di UserLink if nCnt < 2 then return end -- stabilisco l'orientamento del link local bCCW = false -- costruisco la superficie "definita" dal setto local nGrpTmp = EgtGroup( EgtGetParent( nCrv)) local nSrfLoop = EgtCurveCompoFromPoints( nGrpTmp, {EgtEP( nCrv), EgtSP( nCrv + 1)}) EgtAddCurveCompoLine( nSrfLoop, EgtSP( nCrv + 1) + 100 * EgtSV( nCrv + 1)) EgtAddCurveCompoLine( nSrfLoop, EgtEP( nCrv) - 100 * EgtEV( nCrv)) EgtCloseCurveCompo( nSrfLoop) local nSurf = EgtSurfFlatRegion( nGrpTmp, {nSrfLoop}) if not nSurf then EgtErase( nGrpTmp) return end -- verifico direzione della normale local vtN = EgtSurfFrNormVersor( nSurf, GDB_ID.ROOT) if AreSameVectorApprox( vtN, vtSlicing) then bCCW = true end -- setto le info for i = 0, nCnt - 1 do EgtSetInfo( nCrv + i, KEY_RIBS_USER_LINK, 1) EgtSetInfo( nCrv + i, KEY_RIBS_USER_LINK_CCW, bCCW) EgtSetInfo( nCrv + i, KEY_RIBS_USER_LINK_ORDER, i) EgtSetInfo( nCrv + i, KEY_RIBS_USER_LINK_TOT, nCnt) end EgtErase( nGrpTmp) end ------------------------------------------------------------------- local function TrimRibs( vRibs, nRibsGrp, nSrf, dSrfOffs, vtSlicing) -- costruisco le superfici con cui fare il trim grossolano dei setti local nSrfInt = EgtCopyGlob( nSrf, nRibsGrp) or GDB_ID.NULL local nSrfExt = EgtCopyGlob( nSrf, nRibsGrp) or GDB_ID.NULL EgtSurfFrOffset( nSrfInt, dSrfOffs) EgtSurfFrOffset( nSrfExt, - dSrfOffs) -- trim dei setti local nTrimmedRibsGrp = EgtGroup( nRibsGrp) for i = 1, #vRibs do local nCopyRib = EgtCopyGlob( vRibs[i], nTrimmedRibsGrp) local nType = EgtGetInfo( vRibs[i], KEY_RIBS_TYPE, 'i') local nCrv, nCnt if nType == RIB_TYPE.INTERNAL or nType == RIB_TYPE.SUPPORT then if EgtSurfFrChunkCount( nSrfInt) == 0 then -- se la superficie non esiste, il setto deve essere cancellato EgtErase( nCopyRib) nCrv = GDB_ID.NULL nCnt = 0 else nCrv, nCnt = EgtTrimCurveWithRegion( nCopyRib, nSrfInt, true, true) end elseif nType == RIB_TYPE.EXTERNAL then if EgtSurfFrChunkCount( nSrfExt) == 0 then -- se la superficie non esiste il setto è valido nCrv = nCopyRib nCnt = 1 else nCrv, nCnt = EgtTrimCurveWithRegion( nCopyRib, nSrfExt, false, true) end else -- setto unbounded non va tagliato nCrv = nCopyRib nCnt = 1 end -- se errore nel calcolare trim ( nCrv = nil) riprendo il setto originario if not nCrv then nCrv = nCopyRib nCnt = 1 end for nId = nCrv, nCrv + nCnt - 1 do EgtSetInfo( nId, KEY_START_RIB, vRibs[i]) -- se originale era chiusa ma è stata spezzata dopo il trim è il caso di LoopRib if EgtCurveIsClosed( vRibs[i]) and nCnt > 1 then EgtSetInfo( nId, KEY_LOOP_RIB, 1) end end -- verifico se link definito dall'utente e ne analizzo le proprietà CheckRibUserLink( nCrv, nCnt, vtSlicing) end return nTrimmedRibsGrp end -------------------------------------------------------------------- local function ComputeRibsOrientedOffset( nRibsGrp, dStrand) local nOffsGrp = EgtGroup( EgtGetParent( nRibsGrp)) local nCurrRib = EgtGetFirstNameInGroup( nRibsGrp, RIBS_CRV .. '*') while nCurrRib do -- recupero tutti i tratti appartenenti a quel setto (hanno lo stesso nome) local sName = EgtGetName( nCurrRib) local vIds = EgtGetNameInGroup( nRibsGrp, sName) -- recupero i parametri del setto local bInvert = EgtGetInfo( nCurrRib, KEY_RIBS_INVERT_DIR, 'b') or false local bInvertOrder = EgtGetInfo( nCurrRib, KEY_RIBS_INVERT_STRAND_ORDER, 'b') or false local nShellsNbr = EgtGetInfo( nCurrRib, KEY_RIBS_SHELLS_NBR, 'i') local dOffs = ( nShellsNbr - 1) * dStrand / 2 -- offset di ogni tratto del setto local vOffs = {} local bPlusToMinus = false for i = 1, #vIds do local bUserLinked = EgtGetInfo( vIds[i], KEY_RIBS_USER_LINK, 'b') or false local bCCW = EgtGetInfo( vIds[i], KEY_RIBS_USER_LINK_CCW, 'b') or false local nLinkOrder = EgtGetInfo( vIds[i], KEY_RIBS_USER_LINK_ORDER, 'i') or 0 -- ordine di realizzazione degli offset if not bUserLinked then bPlusToMinus = false else if nLinkOrder == 0 then -- determinato dal verso del collegamento bPlusToMinus = EgtIf( bCCW, true, false) else bPlusToMinus = not bPlusToMinus end end for k = 0, nShellsNbr - 1 do local dOffsCurr = dOffs - k * dStrand local nNewId if abs( dOffsCurr) < GEO.EPS_SMALL then nNewId = EgtCopyGlob( vIds[i], nOffsGrp) else nNewId = EgtOffsetCurveAdv( vIds[i], EgtIf( bPlusToMinus, dOffsCurr, - dOffsCurr)) end if nNewId then EgtSetName( nNewId, sName) EgtSetInfo( nNewId, KEY_TYPE, TYPE.RIB) EgtSetInfo( nNewId, KEY_ORIGINAL_RIB, vIds[i]) EgtRelocateGlob( nNewId, nOffsGrp) table.insert( vOffs, nNewId) end end end -- ordinamento if bInvertOrder then for i = 1, #vOffs - 1 do EgtRelocateGlob( vOffs[i], vOffs[#vOffs], GDB_IN.AFTER) end -- aggiorno il vettore con gli indici per rispettare nuovo ordinamento vOffs = EgtGetNameInGroup( nOffsGrp, sName) end -- orientamento local bInvertCrv = bInvert for j = 1, #vOffs, nShellsNbr do -- stabilisco orientamento del primo tratto del gruppo local bUserLinked = EgtGetInfo( vOffs[j], KEY_RIBS_USER_LINK, 'b') or false local nLinkOrder = EgtGetInfo( vOffs[j], KEY_RIBS_USER_LINK_ORDER, 'i') or 0 local nLinkTot = EgtGetInfo( vOffs[j], KEY_RIBS_USER_LINK_TOT, 'i') or 0 if not bUserLinked then bInvertCrv = bInvert else if ( not bInvertOrder and nLinkOrder == 0) or ( bInvertOrder and nLinkOrder == nLinkTot - 1) then bInvertCrv = bInvert if ( nShellsNbr % 2 == 0 and not bInvertOrder) or ( nShellsNbr % 2 ~= 0 and bInvertOrder) then bInvertCrv = not bInvert end else if nShellsNbr % 2 == 0 then bInvertCrv = not bInvertCrv end end end -- inversione for k = 0, nShellsNbr - 1 do if ( bInvertCrv and k % 2 == 0) or ( not bInvertCrv and k % 2 ~= 0) then EgtInvertCurve( vOffs[j + k]) UpdateInvertInfo( vOffs[j + k]) end end end -- passo al setto successivo nCurrRib = EgtGetNextName( vIds[#vIds], RIBS_CRV .. '*') end return nOffsGrp end -------------------------------------------------------------------- local function ComputeTrimSurfWithOverlapsForRibs( vIds, nSrfBase, nSrfExt, dOffs, dStrand, nGrp, vtSlicing) -- per ogni tipologia e overlap creo le superfici con cui fare i trim local tSurfOffs = {{}, {}, {}, {}} for i = 1, #vIds do local nOverlap = EgtGetInfo( vIds[i], KEY_RIBS_OVERLAP, 'i') local nType = EgtGetInfo( vIds[i], KEY_RIBS_TYPE, 'i') if not tSurfOffs[nType][nOverlap] then if nType == RIB_TYPE.INTERNAL or nType == RIB_TYPE.SUPPORT then if nSrfBase ~= GDB_ID.NULL then local dNewOffs = nOverlap / 100 * dStrand local bOk, bExists, nSrfOffs = ComputeSurfOffset( nSrfBase, nGrp, dNewOffs, vtSlicing) if bOk then tSurfOffs[RIB_TYPE.INTERNAL][nOverlap] = nSrfOffs tSurfOffs[RIB_TYPE.SUPPORT][nOverlap] = nSrfOffs end end elseif nType == RIB_TYPE.EXTERNAL then if nSrfExt ~= GDB_ID.NULL then local dNewOffs = dOffs + ( 0.5 - nOverlap / 100) * dStrand local bOk, bExists, nSrfOffs = ComputeSurfOffset( nSrfExt, nGrp, dNewOffs, vtSlicing) if bOk then tSurfOffs[nType][nOverlap] = nSrfOffs EgtSetName( nSrfOffs, TOT_SHELL_TRIM_SURF) end else -- se la superficie non esiste, il setto è sicuramente esterno (è analogo ad unbounded) tSurfOffs[nType][nOverlap] = GDB_ID.NULL end else tSurfOffs[nType][nOverlap] = GDB_ID.NULL end end end return tSurfOffs end -------------------------------------------------------------------- local function VerifyRibsIntersection( nRib1, nRib2, nType1, nType2, nSrf1, nSrf2, dStrand, nGrp, nOffsGrp) -- setti interni/supporto ed esterni non si possono intersecare per definizione if ( ( nType1 == RIB_TYPE.INTERNAL or nType1 == RIB_TYPE.SUPPORT) and nType2 == RIB_TYPE.EXTERNAL) or ( nType1 == RIB_TYPE.EXTERNAL and ( nType2 == RIB_TYPE.INTERNAL or nType2 == RIB_TYPE.SUPPORT)) then return false end -- se hanno lo stesso nome derivano dalla stessa costolatura quindi non ha senso controllare intersezione if EgtGetName( nRib1) == EgtGetName( nRib2) then return false end local bInters = false local bForceCrv1Cut = false -- porto le curve nel gruppo locale local nCrv1 = EgtCopyGlob( nRib1, nGrp) local nCrv2 = EgtCopyGlob( nRib2, nGrp) -- verifico se si intersecano nel piano XY definito dal gruppo locale local nId, nPntCnt, nCrvCnt = EgtCurveCurveInters( nCrv1, nCrv2, nGrp) -- se si intersecano verifico se ho intersezioni valide if nId then -- scorro tutti i punti di intersezione trovati for i = 0, nPntCnt - 1 do local nPtId = nId + i -- verifico se valida if nType1 == RIB_TYPE.UNBOUNDED and nType2 == RIB_TYPE.UNBOUNDED then -- nel caso unbounded l'intersezione può essere ovunque bInters = true elseif nType1 == RIB_TYPE.EXTERNAL or nType2 == RIB_TYPE.EXTERNAL then if nSrf2 then -- l'intersezione deve essere esterna if EgtSurfFrTestExternal( nSrf2, nPtId) then bInters = true end else -- se la surf non esiste l'intersezione è sicuramente esterna bInters = true end else -- se uno dei due è interno o supporto l'intersezione deve essere interna if nSrf1 and not EgtSurfFrTestExternal( nSrf1, nPtId) then bInters = true end end -- se valida verifico se forza il taglio sulla curva 1 if bInters then local ptInt = EgtSP( nPtId, GDB_ID.ROOT) local dPar1 = EgtCurveParamAtPoint( nCrv1, ptInt, GEO.EPS_SMALL, GDB_RT.GLOB) local dPar2 = EgtCurveParamAtPoint( nCrv2, ptInt, GEO.EPS_SMALL, GDB_RT.GLOB) local _, dParE1 = EgtCurveDomain( nCrv1) local _, dParE2 = EgtCurveDomain( nCrv2) local bCrv1OnExtr = ( dPar1 < 10 * GEO.EPS_SMALL or abs( dPar1 - dParE1) < 10 * GEO.EPS_SMALL) local bCrv2OnExtr = ( dPar2 < 10 * GEO.EPS_SMALL or abs( dPar2 - dParE2) < 10 * GEO.EPS_SMALL) bForceCrv1Cut = ( bCrv1OnExtr and not bCrv2OnExtr) if bForceCrv1Cut then return bInters, bForceCrv1Cut -- true, true end end end return bInters, bForceCrv1Cut -- true/false, false else -- se non si intersecano, verifico se si intersecano i loro offset local vOffs1 = EgtGetNameInGroup( nOffsGrp, EgtGetName( nCrv1)) or {} local vOffs2 = EgtGetNameInGroup( nOffsGrp, EgtGetName( nCrv2)) or {} for i = 1, #vOffs1 do local nSrfOffs1 = EgtSurfFrFatCurve( nGrp, vOffs1[i], 0.5 * dStrand, false) if nSrfOffs1 then for j = 1, #vOffs2 do -- verifico se intersezione local nRes = EgtCurveWithRegionClassify( vOffs2[j], nSrfOffs1) if nRes == GDB_CRC.IN or nRes == GDB_CRC.INTERS then bInters = true break end end if bInters then break end end end return bInters, bForceCrv1Cut -- true, false end end --------------------------------------------------------------------------------- -- Funzione che sistema le intersezioni fra costolature nel caso generico local function AdjustRibsOffsetForIntersection( nCrv1, nCrv2, LayerParams, nOffsGrp, bSaveSurf, nLoopGrp) -- calcolo la superficie della curva principale ( nCrv1) da usare per trim local nShells = EgtGetInfo( nCrv1, KEY_RIBS_SHELLS_NBR, 'i') local nOverlap = EgtGetInfo( nCrv2, KEY_RIBS_OVERLAP, 'i') local dOffs = ( nShells - 1) * LayerParams.dStrand / 2 local nSrf = EgtSurfFrFatCurve( nOffsGrp, nCrv1, dOffs + ( 1 - nOverlap / 100) * LayerParams.dStrand, false) if not nSrf then return end -- trim degli offset della curva secondaria ( nCrv2) local vOffs2 = EgtGetNameInGroup( nOffsGrp, EgtGetName( nCrv2)) or {} for i = 1, #vOffs2 do local nId, nCnt = EgtTrimCurveWithRegion( vOffs2[i], nSrf, false, true) -- se setto chiuso verifico se primo e ultimo tratto possono essere uniti if EgtCurveIsClosed( nCrv2) then if nCnt > 1 and AreSamePointApprox( EgtEP( nId + nCnt - 1), EgtSP( nId)) then EgtRelocateGlob( nId + nCnt - 1, nId, GDB_IN.AFTER) EgtAddCurveCompoCurve( nId + nCnt - 1, nId) EgtChangeId( nId + nCnt - 1, nId) nCnt = nCnt - 1 end end -- aggiorno ordine di split copiandolo da nCrv2 for j = nId, nId + nCnt - 1 do CopyInfo( nCrv2, j, KEY_SPLIT_ORDER, 'i') end end -- se necessario salvo i loop da usare per ingressi e uscite if bSaveSurf then -- verifico orientamento della superficie per compatibilità ingressi ribs splittati local vtN = EgtSurfFrNormVersor( nSrf) if AreSameVectorApprox( vtN, LayerParams.vtSlicing) then EgtInvertSurf( nSrf) end local nChunks = EgtSurfFrChunkCount( nSrf) for i = 0, nChunks - 1 do local nRes, nCnt = EgtExtractSurfFrChunkLoops( nSrf, i, nLoopGrp) for j = nRes, nRes + nCnt - 1 do EgtSetName( j, SURF_LOOP) end end end EgtErase( nSrf) end -------------------------------------------------------------------- -- Funzione che sistema le intersezioni fra costolature nel caso di 2 passate local function AdjustRibsOffsetForIntersection2Shells( nCrv1, nCrv2, LayerParams, nOffsGrp) -- costruisco le superfici da usare per trim local nSrf1 = EgtSurfFrFatCurve( nOffsGrp, nCrv1, LayerParams.dStrand / 2, false) local vtN1 = EgtSurfFrNormVersor( nSrf1, GDB_ID.ROOT) if LayerParams.vtSlicing * vtN1 < 0 then EgtInvertSurf( nSrf1) end local nSrf2 = EgtSurfFrFatCurve( nOffsGrp, nCrv2, LayerParams.dStrand / 2, false) local vtN2 = EgtSurfFrNormVersor( nSrf2, GDB_ID.ROOT) if LayerParams.vtSlicing * vtN2 < 0 then EgtInvertSurf( nSrf2) end -- trim degli offset di nCrv1 local vOffs1 = EgtGetNameInGroup( nOffsGrp, EgtGetName( nCrv1)) for i = 1, #vOffs1 do local nId, nCnt = EgtTrimCurveWithRegion( vOffs1[i], nSrf2, false, true) end -- trim degli offset di nCrv2 local vOffs2 = EgtGetNameInGroup( nOffsGrp, EgtGetName( nCrv2)) for i = 1, #vOffs2 do local nId, nCnt = EgtTrimCurveWithRegion( vOffs2[i], nSrf1, false, true) end EgtErase( nSrf1) EgtErase( nSrf2) end ------------------------------------------------------------------ local function UpdateSplitOrder( nCrv, tInters, nOffsGrp) local nOrder = EgtGetInfo( nCrv, KEY_SPLIT_ORDER, 'i') or 0 local nNewOrder = nOrder + 1 -- aggiorno tutte le curve che dipendono da nCrv if tInters[nCrv] then for i = 1, #tInters[nCrv] do local nOldOrder = EgtGetInfo( tInters[nCrv][i], KEY_SPLIT_ORDER, 'i') if nOldOrder < nNewOrder then EgtSetInfo( tInters[nCrv][i], KEY_SPLIT_ORDER, nNewOrder) -- aggiorno i suoi offset local vOffs = EgtGetNameInGroup( nOffsGrp, EgtGetName( tInters[nCrv][i])) for j = 1, #vOffs do EgtSetInfo( vOffs[j], KEY_SPLIT_ORDER, nNewOrder) end -- aggiorno eventuali dipendenze UpdateSplitOrder( tInters[nCrv][i], tInters, nOffsGrp) end end end end --------------------------------------------------------------------------------- local function HandleRibsIntersections( nRibsGrp, LayerParams, nOffsGrp, nRibsPathGrp, nLoopGrp, bAllTwoStrands, vTypeSequence) local bSpecialCase = false local vRibsIds = EgtGetNameInGroup( nRibsGrp, RIBS_CRV .. '*') -- copio gli offset delle costolature nel RibsPathGrp local nCrvGrp = EgtGetParent( nRibsPathGrp) local vOffsRib = EgtGetAllInGroup( nOffsGrp) for i = 1, #vOffsRib do EgtCopyGlob( vOffsRib[i], nRibsPathGrp) end -- creo un gruppo con frame locale per calcolare le intersezioni ( è il piano XY locale dove calcolare intersezioni) local frLoc = Frame3d( ORIG(), LayerParams.vtSlicing) local nGrpTmp = EgtGroup( nRibsGrp, frLoc, GDB_RT.GLOB) -- calcolo le regioni nella quali ha senso considerare l'intersezione local nSrfOffs1, nSrfOffs2 local bOk, bExists local nSrf1 = EgtGetFirstNameInGroup( nCrvGrp, TOT_SHELL_TRIM_SURF) or GDB_ID.NULL if nSrf1 ~= GDB_ID.NULL then bOk, bExists, nSrfOffs1 = ComputeSurfOffset( nSrf1, nCrvGrp, 2 * LayerParams.dStrand, LayerParams.vtSlicing) if not bOk or not bExists then nSrfOffs1 = EgtCopyGlob( nSrf1, nCrvGrp) end end local nSrf2 = EgtGetFirstNameInGroup( nCrvGrp, LAYER_SRF) or GDB_ID.NULL if nSrf2 ~= GDB_ID.NULL then bOk, bExists, nSrfOffs2 = ComputeSurfOffset( nSrf2, nCrvGrp, - 2 * LayerParams.dStrand, LayerParams.vtSlicing) if not bOk or not bExists then nSrfOffs2 = EgtCopyGlob( nSrf2, nCrvGrp) end end local bInters = false local vSplit = {} local tInters = {} -- tabella che tiene traccia delle intersezioni trovate for i = 1, #vRibsIds do local nType1 = EgtGetInfo( vRibsIds[i], KEY_RIBS_TYPE, 'i') -- verifico se interseca uno dei setti successivi for j = i + 1, #vRibsIds do local nType2 = EgtGetInfo( vRibsIds[j], KEY_RIBS_TYPE, 'i') local bRibInters, bForceCrv1Cut = VerifyRibsIntersection( vRibsIds[i], vRibsIds[j], nType1, nType2, nSrfOffs1, nSrfOffs2, LayerParams.dStrand, nGrpTmp, nOffsGrp) if bRibInters then bInters = true local nCrv1 = vRibsIds[i] -- curva principale che non viene tagliata local nCrv2 = vRibsIds[j] -- curve secondaria da modificare local nSplitOrder1 = EgtGetInfo( nCrv1, KEY_SPLIT_ORDER, 'i') or 0 local nSplitOrder2 = EgtGetInfo( nCrv2, KEY_SPLIT_ORDER, 'i') or 0 if bForceCrv1Cut then nCrv1, nCrv2 = nCrv2, nCrv1 nSplitOrder1, nSplitOrder2 = nSplitOrder2, nSplitOrder1 else -- se stessa tipologia taglio il setto già splittato più volte, altrimenti taglio il setto che viene realizzato successivamente if ( nType1 == nType2 and nSplitOrder1 > nSplitOrder2) or ( nType1 ~= nType2 and vTypeSequence[nType1] > vTypeSequence[nType2]) then nCrv1, nCrv2 = nCrv2, nCrv1 nSplitOrder1, nSplitOrder2 = nSplitOrder2, nSplitOrder1 end end -- aggiorno tabella delle intersezioni local bSaveSurf = false if tInters[nCrv1] then table.insert( tInters[nCrv1], nCrv2) else tInters[nCrv1] = {nCrv2} -- è la prima volta che nCrv1 viene usata per un trim quindi devo salvare la superficie utilizzata bSaveSurf = true end -- aggiorno ordine di split if nSplitOrder2 < nSplitOrder1 + 1 then EgtSetInfo( nCrv2, KEY_SPLIT_ORDER, nSplitOrder1 + 1) UpdateSplitOrder( nCrv2, tInters, nRibsPathGrp) end if bAllTwoStrands and ( nType1 == nType2) then -- nel caso di 2 passate e stessa tipologia gestione speciale per creare unico percorso AdjustRibsOffsetForIntersection2Shells( nCrv1, nCrv2, LayerParams, nRibsPathGrp) bSpecialCase = true else AdjustRibsOffsetForIntersection( nCrv1, nCrv2, LayerParams, nRibsPathGrp, bSaveSurf, nLoopGrp) end end end end EgtErase( nSrfOffs1) EgtErase( nSrfOffs2) EgtErase( nGrpTmp) return bInters, bSpecialCase end --------------------------------------------------------------------- local function ReorderSplitRibs( vIds, dStrand, bParamInvertOrder) -- individuo i setti che derivano da uno stesso pezzo di costolatura local tabRibs = {} for i = 1, #vIds do local nOrigId = EgtGetInfo( vIds[i], KEY_ORIGINAL_RIB, 'i') if tabRibs[nOrigId] then table.insert( tabRibs[nOrigId], vIds[i]) else tabRibs[nOrigId] = { vIds[i]} end end for k, tabVal in pairs( tabRibs) do -- verifico se split dopo intersezione con altro setto local nSplitOrder = EgtGetInfo( tabVal[1], KEY_SPLIT_ORDER, 'i') or 0 -- verifico se split dopo aver fatto il trim con la superficie local nStartRib = EgtGetInfo( tabVal[1], KEY_START_RIB, 'i') local bSplitAfterTrim = EgtGetInfo( nStartRib, KEY_SPLIT_AFTER_TRIM, 'b') or false if nSplitOrder > 0 or bSplitAfterTrim then -- caso di setti splittati local nShells = EgtGetInfo( tabVal[1], KEY_RIBS_SHELLS_NBR, 'i') if nShells == 1 then -- non è necessario il riordino, associo splitId diversi ad ogni tratto per gestire correttamente il link nel CalcToolPath for i = 1, #tabVal do EgtSetInfo( tabVal[i], KEY_SPLIT_ID, i) end else -- associo le curve dello split local tAssociatedRibs = {} while #tabVal > 0 do local nCurrId = tabVal[1] table.remove( tabVal, 1) table.insert( tAssociatedRibs, { nCurrId}) local bCurrSplitAfterTrim = EgtGetInfo( nCurrId, KEY_SPLIT_AFTER_TRIM, 'b') or false while nCurrId do local ptCurr = EgtMP( nCurrId) bFound = false for j = 1, #tabVal do local dDist1 = EgtPointCurveDist( ptCurr, tabVal[j]) local dDist2 = EgtPointCurveDist( EgtMP( tabVal[j]), nCurrId) if dDist1 < dStrand + 10 * GEO.EPS_SMALL or dDist2 < dStrand + 10 * GEO.EPS_SMALL then -- verifico nel caso di setti splittati dopo il trim che siano compatibili local bUserLink = EgtGetInfo( tabVal[j], KEY_RIBS_USER_LINK, 'b') or false local bSplitAfterTrim = EgtGetInfo( tabVal[j], KEY_SPLIT_AFTER_TRIM, 'b') or false if bSplitAfterTrim ~= bCurrSplitAfterTrim then if not bCurrSplitAfterTrim and bSplitAfterTrim then local nOrd = EgtGetInfo( tabVal[j], KEY_SPLIT_AFTER_TRIM_ORDER, 'i') if nOrd == 0 then bFound = true end end if bCurrSplitAfterTrim then local nOrd = EgtGetInfo( nCurrId, KEY_SPLIT_AFTER_TRIM_ORDER, 'i') local nTot = EgtGetInfo( nCurrId, KEY_SPLIT_AFTER_TRIM_TOT, 'i') if nOrd == nTot - 1 then bFound = true end end else bFound = true end if bFound then EgtRelocateGlob( tabVal[j], nCurrId, GDB_IN.AFTER) nCurrId = tabVal[j] bCurrSplitAfterTrim = bSplitAfterTrim table.remove( tabVal, j) table.insert( tAssociatedRibs[#tAssociatedRibs], nCurrId) break end end end if not bFound then nCurrId = nil end end end -- assegno splitid per gestire correttamente il link nel CalcToolPath for i = 1, #tAssociatedRibs do for j = 1, #tAssociatedRibs[i] do EgtSetInfo( tAssociatedRibs[i][j], KEY_SPLIT_ID, i) end end -- modifiche per preservare i link definiti dall'utente local bUserLink = EgtGetInfo( tAssociatedRibs[1][1], KEY_RIBS_USER_LINK, 'b') or false if bUserLink and nShells % 2 == 0 then local nLinkOrder = EgtGetInfo( tAssociatedRibs[1][1], KEY_RIBS_USER_LINK_ORDER, 'i') or 0 local nTotParts = EgtGetInfo( tAssociatedRibs[1][1], KEY_RIBS_USER_LINK_TOT, 'i') or 1 local bInvertOrder = EgtGetInfo( tAssociatedRibs[1][1], KEY_RIBS_INVERT_STRAND_ORDER, 'b') or false -- ordinamento if ( nTotParts % 2 == 0 and bInvertOrder and nLinkOrder % 2 ~= 0 ) or ( nTotParts % 2 == 0 and not bInvertOrder and nLinkOrder % 2 == 0) or ( nTotParts % 2 ~= 0 and nLinkOrder % 2 == 0) then local vLastGrp = tAssociatedRibs[#tAssociatedRibs] local nPrevId = vLastGrp[#vLastGrp] for i = #tAssociatedRibs - 1, 1, -1 do for j = 1, #tAssociatedRibs[i] do local nCurrId = tAssociatedRibs[i][j] EgtRelocateGlob( nCurrId, nPrevId, GDB_IN.AFTER) nPrevId = nCurrId end end end -- direzione if ( nTotParts % 2 == 0 and nLinkOrder > 0 and nLinkOrder < nTotParts - 1) or ( nTotParts % 2 ~= 0 and not bInvertOrder and nLinkOrder > 0) or ( nTotParts % 2 ~= 0 and bInvertOrder and nLinkOrder < nTotParts - 1) then local vLastGrp = tAssociatedRibs[#tAssociatedRibs] for j = 1, #vLastGrp do EgtInvertCurve( vLastGrp[j]) UpdateInvertInfo( vLastGrp[j]) end end end end end end end -------------------------------------------------------------------- local function ShortestPathForRibs( vRibs, nGrp, bInvertOrder) if not vRibs or #vRibs == 0 then return end -- divido per gruppi di setti ( i gruppi sono identificati dallo stesso nome) local tabRibs = {} local sPrevName = "" for i = 1, #vRibs do local sName = EgtGetName( vRibs[i]) if sName == sPrevName then table.insert( tabRibs[#tabRibs], vRibs[i]) else table.insert( tabRibs, {vRibs[i]}) end sPrevName = sName end -- stabilisco l'ordine di realizzazione dei gruppi di setti local vOrd if #tabRibs == 1 then -- se un solo gruppo ordinamento banale vOrd = {1} else -- se più gruppi ordinamento con shortest path EgtSpInit() for i = 1, #tabRibs do local ptS = EgtSP( tabRibs[i][1], GDB_ID.ROOT) local ptE = EgtEP( tabRibs[i][#tabRibs[i]], GDB_ID.ROOT) EgtSpAddPoint( ptS:getX(), ptS:getY(), ptS:getZ(), 0, 0, ptE:getX(), ptE:getY(), ptE:getZ(), 0, 0) end vOrd = EgtSpCalculate( SHP_TY.OPEN) EgtSpTerminate() end -- creo il vettore con i setti ordinati local vIds = {} local nStart = EgtIf( bInvertOrder, #vOrd, 1) local nEnd = EgtIf( bInvertOrder, 1, #vOrd) local nStep = EgtIf( bInvertOrder, -1, 1) for i = nStart, nEnd, nStep do local vCurrRibs = tabRibs[vOrd[i]] for j = 1, #vCurrRibs do table.insert( vIds, vCurrRibs[j]) end end EgtRelocateGlob( vIds[1], nGrp, GDB_IN.LAST_SON) for i = 2, #vIds do EgtRelocateGlob( vIds[i], vIds[i-1], GDB_IN.AFTER) end end -------------------------------------------------------------------- local function ReorderRibs( nGrp, bInvertOrder, dStrand) local vIds = EgtGetNameInGroup( nGrp, RIBS_CRV .. '*') if not vIds or #vIds == 0 then return end -- riordino setti splittati ReorderSplitRibs( vIds, dStrand, bInvertOrder) -- aggiorno gli id con il nuovo ordinamento vIds = EgtGetNameInGroup( nGrp, RIBS_CRV .. '*') -- raggruppo per tipologia local tRibs = {{}, {}, {}, {}} for i = 1, #vIds do local nType = EgtGetInfo( vIds[i], KEY_RIBS_TYPE, 'i') table.insert( tRibs[nType], vIds[i]) end -- riordino ogni tipologia for j = 1, 4 do local vIds = tRibs[j] -- raggruppo in base allo split order local tSplitOrder = {} local nMaxSplitOrder = 0 for i = 1, #vIds do local nSplitOrder = EgtGetInfo( vIds[i], KEY_SPLIT_ORDER, 'i') or 0 -- eventuale aggiornamento del max split order if nSplitOrder > nMaxSplitOrder then nMaxSplitOrder = nSplitOrder end -- inserisco nella tabella if not tSplitOrder[nSplitOrder] then tSplitOrder[nSplitOrder]= {vIds[i]} else table.insert( tSplitOrder[nSplitOrder], vIds[i]) end end -- riordino ogni ordine di split con shortest path for k = 0, nMaxSplitOrder do ShortestPathForRibs( tSplitOrder[k], nGrp, bInvertOrder) end end end -------------------------------------------------------------------------------------------- local function ReassignInfo( nCrv, nCnt, vOrig) for nId = nCrv, nCrv + nCnt - 1 do local ptS = EgtSP( nId) local ptE = EgtEP( nId) EgtSetInfo( nId, KEY_TYPE, TYPE.RIB) if EgtCurveIsClosed( nId) then EgtSetInfo( nId, KEY_CLOSED_CRV, 1) end local bStart = false local bEnd = false while not bStart and not bEnd do -- scorro le curve originarie per capire da quali deriva for i = 1, #vOrig do local ptSOrig = EgtSP( vOrig[i]) local ptEOrig = EgtEP( vOrig[i]) -- verifico se corrisponde al suo start if AreSamePointApprox( ptS, ptSOrig) or AreSamePointApprox( ptS, ptEOrig) then CopyInfo( vOrig[i], nId, KEY_RIBS_LEAD_IN_INVERT, 'b') CopyInfo( vOrig[i], nId, KEY_RIBS_LEAD_IN_LEN, 'd') CopyInfo( vOrig[i], nId, KEY_ASSOCIATED_SURF, 'i') CopyInfo( vOrig[i], nId, KEY_RIBS_OVERLAP, 'i') CopyInfo( vOrig[i], nId, KEY_RIBS_TYPE, 'i') bStart = true end -- verifico se corrisponde al suo end if AreSamePointApprox( ptE, ptSOrig) or AreSamePointApprox( ptE, ptEOrig) then CopyInfo( vOrig[i], nId, KEY_RIBS_LEAD_OUT_INVERT, 'b') CopyInfo( vOrig[i], nId, KEY_RIBS_LEAD_OUT_LEN, 'd') CopyInfo( vOrig[i], nId, KEY_RIBS_LEAD_OUT_COASTING, 'd') CopyInfo( vOrig[i], nId, KEY_RIBS_LEAD_OUT_WIPE, 'd') CopyInfo( vOrig[i], nId, KEY_RIBS_LEAD_OUT_WIPE_DIR, 'd') bEnd = true end end end end -- dopo aver salvato le info è inutile conservare le curve originali for i = 1, #vOrig do EgtErase( vOrig[i]) end end --------------------------------------------------------------------------------------------- -- Funzione che riordina le costolature nel caso di intersezioni e 2 passate local function ReorderRibsInters2Shells( nOffsGrp, dStrand, bInvertOrder) local vOffs = {} local vClosed = {} local nId = EgtGetFirstNameInGroup( nOffsGrp, RIBS_CRV .. '*') while nId do if EgtCurveIsClosed( nId) then table.insert( vClosed, nId) else table.insert( vOffs, nId) end nId = EgtGetNextName( nId, RIBS_CRV .. '*') end local k = 0 -- indice da utilizzare per i nomi -- gestione delle curve chiuse if #vClosed > 0 then k = k + 1 local sPrevName = EgtGetName( vClosed[1]) EgtSetName( vClosed[1], RIBS_CRV .. tostring( k)) for i = 2, #vClosed do local sCurrName = EgtGetName( vClosed[i]) -- se setto diverso aggiorno il nome if sCurrName ~= sPrevName then k = k + 1 end EgtSetName( vClosed[i], RIBS_CRV .. tostring( k)) sPrevName = sCurrName end end -- gestione delle curve aperte -- copio le curve originali ( per recuperarne le info) local vCopy = {} for i = 1, #vOffs do local nNewId = EgtCopy( vOffs[i], nOffsGrp) table.insert( vCopy, nNewId) end -- concateno le curve local nCrv, nCnt = EgtCurveCompoByChain( nOffsGrp, vOffs, ORIG()) local vIds = {} for i = nCrv, nCrv + nCnt - 1 do table.insert( vIds, i) end -- recupero le info dalle curve originali ReassignInfo( nCrv, nCnt, vCopy) while #vIds > 0 do k = k + 1 -- prendo la prima tra le curve a disposizione nCurrCrv = vIds[1] table.remove( vIds, 1) EgtSetName( nCurrCrv, RIBS_CRV .. tostring(k)) local pt = EgtEP( nCurrCrv) local _, dParE = EgtCurveDomain( nCurrCrv) local nCnt = 0 -- scorro alla ricerca di una curva che posso collegare alla corrente while nCurrCrv do local nCurrType = EgtGetInfo( nCurrCrv, KEY_RIBS_TYPE, 'i') local bFound = false for j = 1, #vIds do local nType = EgtGetInfo( vIds[j], KEY_RIBS_TYPE, 'i') if vIds[j] ~= nCrv and not EgtCurveIsClosed(vIds[j]) and nCurrType == nType then -- verifico se il collegamento è possibile local bAdd = false local bInvert = false local dDist, _, dParMinDist = EgtPointCurveDist( pt, vIds[j]) if dDist < dStrand + 10 * GEO.EPS_SMALL then -- controllo che sia vicino ad uno degli estremi local dParS, dParE = EgtCurveDomain( vIds[j]) if abs( dParMinDist - dParS) < 500 * GEO.EPS_SMALL then bAdd = true elseif abs( dParMinDist - dParE) < 500 * GEO.EPS_SMALL then bAdd = true -- è se necessaria inversione di vIds[j] bInvert = true end end if not bAdd then -- check sullo start point di vIds[j] local dDist, _, dParMinDist = EgtPointCurveDist( EgtSP( vIds[j]), nCurrCrv) if dDist < dStrand + 10 * GEO.EPS_SMALL then bInvert = false -- controllo sia vicino all'end point della curva corrente if dParE - dParMinDist < 500 * GEO.EPS_SMALL then bAdd = true -- altrimenti può essere vicino allo start elseif dParMinDist < 500 * GEO.EPS_SMALL and nCnt == 0 then bAdd = true EgtInvertCurve( nCurrCrv) end end -- se non è aggiunto check con end point di vIds[j] if not bAdd then local dDist, _, dParMinDist = EgtPointCurveDist( EgtEP( vIds[j]), nCurrCrv) if dDist < dStrand + 10 * GEO.EPS_SMALL then bInvert = true if dParE - dParMinDist < 500 * GEO.EPS_SMALL then bAdd = true elseif dParMinDist < 500 * GEO.EPS_SMALL and nCnt == 0 then bAdd = true EgtInvertCurve( nCurrCrv) end end end end if bAdd then bFound = true nCnt = nCnt + 1 EgtRelocateGlob( vIds[j], nCurrCrv, GDB_IN.AFTER) EgtSetName( vIds[j], RIBS_CRV .. tostring( k)) -- eventuale inversione della curva if bInvert then EgtInvertCurve( vIds[j]) end -- aggiorno per collegamento successivo pt = EgtEP( vIds[j]) _, dParE = EgtCurveDomain( vIds[j]) nCurrCrv = vIds[j] -- elimino la curva dal vettore di curve da considerare table.remove( vIds, j) break end end end -- se non ho più curve da collegare if not bFound and nCnt == 0 then -- se era la prima curva faccio un tentativo invertendola nCnt = 1 EgtInvertCurve( nCurrCrv) pt = EgtEP( nCurrCrv) elseif not bFound then nCurrCrv = nil end end end -- eventuale inversione ordinamento if bInvertOrder then local vRibs = EgtGetNameInGroup( nOffsGrp, RIBS_CRV .. '*') for j = #vRibs, 1, -1 do -- inverto direzione curve per mantenere concatenamento EgtInvertCurve( vRibs[j]) EgtRelocateGlob( vRibs[j], nOffsGrp, GDB_IN.LAST_SON) end end end ------------------------------------------------------------------- local function CalcRibsPaths( nSliceGrp, nRibsGrp, LayerParams, nIdx, vPtStart) -- stabilisco ordine di realizzazione delle varie tipologie local vTypeSequence = {} for i = 1, #LayerParams.vPrintOrder do if LayerParams.vPrintOrder[i] == PRINT_ELEMENT.RIB_UNBOUNDED then vTypeSequence[RIB_TYPE.UNBOUNDED] = i elseif LayerParams.vPrintOrder[i] == PRINT_ELEMENT.RIB_INTERNAL then vTypeSequence[RIB_TYPE.INTERNAL] = i elseif LayerParams.vPrintOrder[i] == PRINT_ELEMENT.RIB_EXTERNAL then vTypeSequence[RIB_TYPE.EXTERNAL] = i elseif LayerParams.vPrintOrder[i] == PRINT_ELEMENT.RIB_SUPPORT then vTypeSequence[RIB_TYPE.SUPPORT] = i end end local vOrigRibs = EgtGetNameInGroup( nRibsGrp, RIBS_CRV .. '*') -- verifico se tutte le costolature vengono fatte con 2 passate local bAllTwoStrands = true for i = 1, #vOrigRibs do local nStrand = EgtGetInfo( vOrigRibs[i], KEY_RIBS_SHELLS_NBR, 'i') if nStrand ~= 2 then bAllTwoStrands = false break end end -- verifico se posso ignorare eventuali buchi nei setti VerifyRibsHoles( vOrigRibs, LayerParams.dStrand) -- scorro i gruppi di curve local nCrvGrp = EgtGetFirstNameInGroup( nSliceGrp, CONTOUR_GRP .. '*') while nCrvGrp do -- creo o svuoto il gruppo local nRibsPathGrp = EgtGetFirstNameInGroup( nCrvGrp, RIBS_GRP) if not nRibsPathGrp then nRibsPathGrp = EgtGroup( nCrvGrp) EgtSetName( nRibsPathGrp, RIBS_GRP) EgtSetStatus( nRibsPathGrp, GDB_ST.OFF) else EgtEmptyGroup( nRibsPathGrp) end -- recupero le superfici local nSrfBase = EgtGetFirstNameInGroup( nCrvGrp, TOT_SHELL_TRIM_SURF) or GDB_ID.NULL local nSrfExt = EgtGetFirstNameInGroup( nCrvGrp, LAYER_SRF) or GDB_ID.NULL -- trim grossolano dei setti local nTrimGrp = TrimRibs( vOrigRibs, nRibsGrp, nSrfExt, LayerParams.dOffs - LayerParams.dStrand / 2, LayerParams.vtSlicing) -- calcolo offset orientati local nOffsGrp = ComputeRibsOrientedOffset( nTrimGrp, LayerParams.dStrand) -- creo le superfici con cui fare i trim corretti local tSurfOffs = ComputeTrimSurfWithOverlapsForRibs( vOrigRibs, nSrfBase, nSrfExt, LayerParams.dOffs, LayerParams.dStrand, nRibsPathGrp, LayerParams.vtSlicing) -- preparo il gruppo con i contorni delle superfici di offset ( necessario per CalcToolPath) local nLoopGrp = EgtGroup( nRibsPathGrp) local nSrfId = EgtGetFirstNameInGroup( nRibsPathGrp, TOT_SHELL_TRIM_SURF) while nSrfId do local nChunksNbr = EgtSurfFrChunkCount( nSrfId) for i = 0, nChunksNbr - 1 do local nRes, nCnt = EgtExtractSurfFrChunkLoops( nSrfId, i, nLoopGrp) for j = nRes, nRes + nCnt - 1 do EgtSetName( j, TRIM_SURF_LOOP) end end nSrfId = EgtGetNextName( nSrfId, TOT_SHELL_TRIM_SURF) end -- gestisco eventuali intersezioni fra costolature local bInters, bSpecialCase = HandleRibsIntersections( nRibsGrp, LayerParams, nOffsGrp, nRibsPathGrp, nLoopGrp, bAllTwoStrands, vTypeSequence) EgtSetInfo( nRibsPathGrp or GDB_ID.NULL, KEY_RIBS_INTERS, bInters) EgtSetInfo( nRibsPathGrp or GDB_ID.NULL, KEY_RIBS_SPECIAL_CASE, bSpecialCase) -- trim dei setti con le regioni offsettate secondo opportuno overlap local vRibs = EgtGetNameInGroup( nRibsPathGrp, RIBS_CRV ..'*') or {} for i = 1, #vRibs do local nCrvId = vRibs[i] -- trim con superficie opportuna local nOverlap = EgtGetInfo( nCrvId, KEY_RIBS_OVERLAP, 'i') local nType = EgtGetInfo( nCrvId, KEY_RIBS_TYPE, 'i') if not tSurfOffs[nType][nOverlap] then -- la costolatura non è fattibile EgtOutLog( 'Warning: Ribs not possibile (layer '..tostring( nIdx)..') - CalcPaths') EgtErase( vRibs[i]) else local nCrv, nCnt if tSurfOffs[nType][nOverlap] == GDB_ID.NULL then -- caso unbounded o esterno in assenza di solido nCrv = nCrvId nCnt = 1 else nCrv, nCnt = EgtTrimCurveWithRegion( nCrvId, tSurfOffs[nType][nOverlap], EgtIf( nType == RIB_TYPE.INTERNAL or nType == RIB_TYPE.SUPPORT, true, false), false) end for nInd = 0, nCnt - 1 do -- verifico vicolo sulla lunghezza local dLen = EgtCurveLength( nCrv + nInd) if dLen < MIN_RIBS_LEN then EgtErase( nCrv + nInd) else -- salvo info della superficie di trim associata EgtSetInfo( nCrv + nInd, KEY_ASSOCIATED_SURF, tSurfOffs[nType][nOverlap]) -- setti chiusi if EgtCurveIsClosed( nCrv + nInd) then EgtSetInfo( nCrv + nInd, KEY_CLOSED_CRV, 1) -- ripristino orientamento originale local bInvertInfo = EgtGetInfo( nCrv + nInd, KEY_RIBS_INVERT_DIR, 'b') or false local bInverted = EgtGetInfo( nCrv + nInd, KEY_INVERTED_CRV, 'b') or false if bInvertInfo ~= bInverted then EgtInvertCurve( nCrv + nInd) UpdateInvertInfo( nCrv + nInd) end ModifyStartPoint( nCrv + nInd, vPtStart) EgtSetInfo( nCrv + nInd, KEY_RIBS_LINK, 0) end -- se dopo trim ho avuto split in più tratti, salvo alcune info if nCnt > 1 then local nStartRib = EgtGetInfo( nCrv + nInd, KEY_START_RIB, 'i') EgtSetInfo( nStartRib, KEY_SPLIT_AFTER_TRIM, 1) EgtSetInfo( nCrv + nInd, KEY_SPLIT_AFTER_TRIM, 1) EgtSetInfo( nCrv + nInd, KEY_SPLIT_AFTER_TRIM_ORDER, nInd) EgtSetInfo( nCrv + nInd, KEY_SPLIT_AFTER_TRIM_TOT, nCnt) end end end end end -- riordino le costolature if bSpecialCase then -- gestione caso speciale di intersezione e 2 passate ReorderRibsInters2Shells( nRibsPathGrp, LayerParams.dStrand, LayerParams.bRibsInvertOrder) else ReorderRibs( nRibsPathGrp, LayerParams.bRibsInvertOrder, LayerParams.dStrand) end if not EgtGetFirstNameInGroup( nRibsPathGrp, RIBS_CRV .. '*') then EgtErase( nRibsPathGrp) end -- sistemo le quote delle superfici e dei loop per CalcToolPath local vLoopIds = EgtGetAllInGroup( nLoopGrp) or {} for i = 1, #vLoopIds do EgtMove( vLoopIds[i], LayerParams.dLayHeight * LayerParams.vtSlicing, GDB_RT.GLOB) end local vSrfIds = EgtGetNameInGroup( nRibsPathGrp, TOT_SHELL_TRIM_SURF) or {} for i = 1, #vSrfIds do EgtMove( vSrfIds[i], LayerParams.dLayHeight * LayerParams.vtSlicing, GDB_RT.GLOB) end nCrvGrp = EgtGetNextName( nCrvGrp, CONTOUR_GRP .. '*') end end -------------------------------------------------------------------- ----------------- REGIONI CON DIVERSE PASSATE ---------------------- -------------------------------------------------------------------- local function CreateShellNbrSurfaces( nGrp, nShellsNbr) if not nGrp then return end local tDiffCrvs = {} local nMaxShellNbrDiff = 0 local nCrvId = EgtGetFirstNameInGroup( nGrp, SHELL_NBR_CRV .. '*') while nCrvId do if EgtCurveIsClosed( nCrvId) then -- recupero info sul gap local nShellNbrDiff = EgtGetInfo( nCrvId, KEY_SHELL_NBR_DIFF, 'i') -- aggiorno eventuale massimo if nMaxShellNbrDiff < nShellNbrDiff then nMaxShellNbrDiff = nShellNbrDiff end -- salvo gli id delle curve if not tDiffCrvs[nShellNbrDiff] then tDiffCrvs[nShellNbrDiff] = { nCrvId} else table.insert( tDiffCrvs[nShellNbrDiff], nCrvId) end end nCrvId = EgtGetNextName( nCrvId, SHELL_NBR_CRV .. '*') end -- eventuale correzione del numero massimo in base al numero di passate nMaxShellNbrDiff = min( nMaxShellNbrDiff, nShellsNbr) -- costruisco per ogni valore la superficie complessiva local nSrfGrp = EgtGroup( nGrp) for nDiff = 1, nMaxShellNbrDiff do -- recupero gli id delle curve coinvolte local vCrvIds = {} for nG, vIds in pairs( tDiffCrvs) do if nG >= nDiff then for k = 1, #vIds do table.insert( vCrvIds, vIds[k]) end end end -- costruisco la surf local nSrfId = EgtSurfFlatRegion( nSrfGrp, vCrvIds[1]) for i = 2, #vCrvIds do local nSrfTmp = EgtSurfFlatRegion( nSrfGrp, vCrvIds[i]) EgtSurfFrAdd( nSrfId, nSrfTmp) EgtErase( nSrfTmp) end EgtSetName( nSrfId, SHELL_NBR_SURF .. tostring( nDiff)) -- salvo come info gli id delle curve che la definiscono EgtSetInfo( nSrfId, KEY_ASSOCIATED_CRVS, vCrvIds) end end -------------------------------------------------------------------- local function ComputeMaxShellNbrDiff( nSrf, nShellNbrSurfGrp) local nMaxShellNbrDiff = 0 if nShellNbrSurfGrp then local nId = 1 local nShellNbrSrf = EgtGetFirstNameInGroup( nShellNbrSurfGrp, SHELL_NBR_SURF .. tostring( nId)) while nShellNbrSrf do -- se interessa la regione considerata aggiorno il nMaxShellNbrDiff if not EgtSurfFrTestExternal( nSrf, nShellNbrSrf) then nMaxShellNbrDiff = nId end -- passo al successivo nId = nId + 1 nShellNbrSrf = EgtGetFirstNameInGroup( nShellNbrSurfGrp, SHELL_NBR_SURF .. tostring( nId)) end end return nMaxShellNbrDiff end ---------------------------------------------------------------- local function FindExtraShellRetractionParams( ptP, vIds, LayerParams) local dCoasting, dWipe, dWipeDir -- cerco la curva sulla quale si ferma for i = 1, #vIds do local dPar = EgtCurveParamAtPoint( vIds[i], ptP, 10 * GEO.EPS_SMALL) if dPar then dCoasting = EgtGetInfo( vIds[i], KEY_SHELL_NBR_COASTING, 'd') dWipe = EgtGetInfo( vIds[i], KEY_SHELL_NBR_WIPE, 'd') dWipeDir = EgtGetInfo( vIds[i], KEY_SHELL_NBR_WIPE_DIR, 'd') break end end if not dCoasting then -- se non ho trovato una curva considero i parametri generali return LayerParams.dShellNbrCoasting, LayerParams.dShellNbrWipe, LayerParams.dShellNbrWipeDir else return dCoasting, dWipe, dWipeDir end end ----------------------------------------------------------------- local function TrimOuterCurveForExtraShellCalc( nOuterCrv, nSrfDiff, nGrpId, vPtStart, LayerParams) local nCopy = EgtCopyGlob( nOuterCrv, nGrpId) ModifyStartPoint( nCopy, vPtStart) -- recupero tutte le curve delle ShellNumber coinvolte local vShellNbrCrvs = EgtGetInfo( nSrfDiff, KEY_ASSOCIATED_CRVS, 'vi') -- trim della curva local nCrv, nCnt = EgtTrimCurveWithRegion( nCopy, nSrfDiff, false, false) if nCrv and nCnt ~= 0 then -- verifico se prima e ultima curva possono essere unite if nCnt > 1 and AreSamePointApprox( EgtEP( nCrv + nCnt - 1), EgtSP( nCrv)) then EgtRelocateGlob( nCrv + nCnt - 1, nCrv, GDB_IN.AFTER) EgtAddCurveCompoCurve( nCrv + nCnt - 1, nCrv) EgtChangeId( nCrv + nCnt - 1, nCrv) nCnt = nCnt - 1 end -- assegno le info in base alla curva che li delimita for nId = nCrv, nCrv + nCnt - 1 do local ptS = EgtSP( nId) local dCoastingS, dWipeS, dWipeDirS = FindExtraShellRetractionParams( ptS, vShellNbrCrvs, LayerParams) local ptE = EgtEP( nId) local dCoastingE, dWipeE, dWipeDirE = FindExtraShellRetractionParams( ptE, vShellNbrCrvs, LayerParams) EgtSetInfo( nId, KEY_EXTRA_SHELL_COASTING, {dCoastingS, dCoastingE}) EgtSetInfo( nId, KEY_EXTRA_SHELL_WIPE, {dWipeS, dWipeE}) EgtSetInfo( nId, KEY_EXTRA_SHELL_WIPE_DIR, {dWipeDirS, dWipeDirE}) end return nCrv, nCnt else return nOuterCrv, 0 end end -------------------------------------------------------------------- local function UpdateTotalShellSurf( nSrf, nCrv, dStrand, nGrpId) local nSrfExtraShell = EgtSurfFrFatCurve( nGrpId, nCrv, dStrand - s_dOffsCorr, false) if nSrfExtraShell then local vtSrfN = EgtSurfFrNormVersor( nSrf, GDB_ID.ROOT) local vtSrfExShN = EgtSurfFrNormVersor( nSrfExtraShell, GDB_ID.ROOT) if vtSrfExShN * vtSrfN < 0 then EgtInvertSurf( nSrfExtraShell) end EgtSurfFrSubtract( nSrf, nSrfExtraShell) EgtErase( nSrfExtraShell) end end --------------------------------------------------------------------- local function ReorderExtraShells( nPathGrp, dStrand, vPtStart, bPrintInvert) -- verifico se posso unire due tratti consecutivi della stessa shell local nFirst = EgtGetFirstNameInGroup( nPathGrp, EXTRA_SHELL_CRV .. '*') while nFirst do -- recupero tratti appartenenti alla stessa shell local vShells = EgtGetNameInGroup( nPathGrp, EgtGetName( nFirst)) local nCurr = vShells[1] for i = 2, #vShells do if dist( EgtEP( nCurr), EgtSP( vShells[i])) < dStrand + GEO.EPS_SMALL then -- unisco le curve EgtAddCurveCompoLine( nCurr, EgtSP( vShells[i])) EgtAddCurveCompoCurve( nCurr, vShells[i]) else nCurr = vShells[i] end end -- check su prima e ultima curva if nCurr ~= nFirst and dist( EgtEP( nCurr), EgtSP( nFirst)) < dStrand + GEO.EPS_SMALL then -- unisco le curve EgtAddCurveCompoLine( nCurr, EgtSP( nFirst)) EgtAddCurveCompoCurve( nCurr, nFirst) end nFirst = EgtGetNextName( nCurr, EXTRA_SHELL_CRV .. '*') end local vIds = EgtGetNameInGroup( nPathGrp, EXTRA_SHELL_CRV .. '*') if not vIds then return end -- eventuale inversione di tutte le curve if bPrintInvert then for i = 1, #vIds do EgtInvertCurve( vIds[i]) UpdateInvertInfo( vIds[i]) end end -- cerco di creare percorsi local k = 0 -- indice da utilizzare per i nomi while #vIds > 0 do k = k + 1 -- prendo la prima tra le curve a disposizione nCurrCrv = vIds[1] table.remove( vIds, 1) EgtSetName( nCurrCrv, EXTRA_SHELL_CRV .. tostring(k)) local ptSCurr = EgtSP( nCurrCrv) local ptECurr = EgtEP( nCurrCrv) local nCnt = 0 -- se curva è chiusa if EgtCurveIsClosed( nCurrCrv) then ModifyStartPoint( nCurrCrv, vPtStart) -- setto a nil per ripartire subito con curva successiva nCurrCrv = nil end -- scorro alla ricerca di una curva che posso collegare alla corrente while nCurrCrv do local bFound = false for j = 1, #vIds do if not EgtCurveIsClosed( vIds[j]) then local ptS = EgtSP( vIds[j]) local ptE = EgtEP( vIds[j]) local bLink = dist( ptS, ptECurr) < 1.5 * dStrand if dist( ptE, ptECurr) < 1.5 * dStrand then -- congiungo end-end EgtInvertCurve( vIds[j]) EgtSetInfo( vIds[j], KEY_INVERTED_CRV, EgtIf( bPrintInvert, 0, 1)) bLink = true elseif nCnt == 0 and dist( ptS, ptSCurr) < 1.5 * dStrand then -- congiungo start-start EgtInvertCurve( nCurrCrv) EgtSetInfo( nCurrCrv, KEY_INVERTED_CRV, EgtIf( bPrintInvert, 0, 1)) bLink = true end if bLink then nCnt = nCnt + 1 EgtRelocateGlob( vIds[j], nCurrCrv, GDB_IN.AFTER) EgtSetName( vIds[j], EXTRA_SHELL_CRV .. tostring( k)) -- aggiorno per collegamento successivo bFound = true nCurrCrv = vIds[j] ptSCurr = EgtSP( vIds[j]) ptECurr = EgtEP( vIds[j]) table.remove( vIds, j) break end end end -- se non ho più curve da collegare if not bFound then nCurrCrv = nil end end end end -------------------------------------------------------------------- local function CalcExtraShellsPath( nMaxShellNbrDiff, nShellNbrGrp, nCrvGrpId, dOffs, LayerParams, nIdx, vPtStart) local nGrpId = EgtGetFirstNameInGroup( nCrvGrpId, PATH_GRP) -- recupero la superficie occupata dalle shell per trim local nSrfTrim = EgtGetFirstNameInGroup( nCrvGrpId, TOT_SHELL_TRIM_SURF) if not nSrfTrim then EgtOutLog( 'Warning : ExtraInnerShells not possible (layer '..tostring( nIdx)..') - CalcPaths') return end for nInd = nMaxShellNbrDiff, 1, -1 do dOffs = dOffs + LayerParams.dStrand * ( 1 - EgtIf( nInd == LayerParams.nShellsNbr, 0, LayerParams.nStrandOverlap / 100)) local nSrfDiff = EgtGetFirstNameInGroup( nShellNbrGrp, SHELL_NBR_SURF .. tostring( nInd)) local nOuterCrv = EgtGetFirstNameInGroup( nCrvGrpId, OUTER_CRV) while nOuterCrv do -- trim della curva con la superficie local nTrimCrv, nTrimCnt = TrimOuterCurveForExtraShellCalc( nOuterCrv, nSrfDiff, nGrpId, vPtStart, LayerParams) for nCrvT = nTrimCrv, nTrimCrv + nTrimCnt - 1 do -- calcolo offset della curva ( è il percorso della shell) EgtModifyCurveExtrusion( nCrvT, LayerParams.vtSlicing, GDB_RT.GLOB) local nOffs, nOffsCnt = EgtOffsetCurveAdv( nCrvT, - dOffs) EgtErase( nCrvT) for nCrvOffs = nOffs, nOffs + nOffsCnt - 1 do -- trim con la regione già occupata dal altre shell local nCrv, nCnt = EgtTrimCurveWithRegion( nCrvOffs, nSrfTrim, true, true) if nCrv and nCnt ~= 0 then for nId = nCrv, nCrv + nCnt - 1 do local dLen = EgtCurveLength( nId) local bValid = true if EgtCurveIsClosed( nId) then bValid = VerifyPath( nId, LayerParams.dStrand, LayerParams.vtSlicing, nGrpId) end -- verifico se soddisfa vincolo sulla lunghezza if dLen > MIN_LEN and bValid then EgtSetStatus( nId, GDB_ST.ON) EgtModifyCurveExtrusion( nId, LayerParams.vtSlicing, GDB_RT.GLOB) EgtSetName( nId, EXTRA_SHELL_CRV .. tostring( nMaxShellNbrDiff - nInd + 1)) if nInd == LayerParams.nShellsNbr then EgtSetInfo( nId, KEY_TYPE, TYPE.EXTRA_OUTER_SHELL) else EgtSetInfo( nId, KEY_TYPE, TYPE.EXTRA_SHELL) end -- aggiorno la superficie occupata dalle shell con quella appena calcolata (tenendo conto dell'overlap) UpdateTotalShellSurf( nSrfTrim, nId, ( 1 - LayerParams.nStrandOverlap / 100) * LayerParams.dStrand, nGrpId) -- se la superficie si annulla non è possibile realizzare altro, quindi cancello tutte le curve rimaste if EgtSurfFrChunkCount( nSrfTrim) == 0 then for j = nId + 1, nCrv + nCnt - 1 do EgtErase( j) end for j = nCrvT + 1, nTrimCrv + nTrimCnt - 1 do EgtErase( j) end -- aggiorno superficie EgtSurfFrOffset( nSrfTrim, - LayerParams.nStrandOverlap / 100 * LayerParams.dStrand) -- riordino le curve appena create e se possibile creo percorsi chiusi ReorderExtraShells( nGrpId, LayerParams.dStrand, vPtStart, LayerParams.bPrintInvert) return end else EgtErase( nId) end end end end end nOuterCrv = EgtGetNextName( nOuterCrv, OUTER_CRV) end end -- aggiorno superificie EgtSurfFrOffset( nSrfTrim, - LayerParams.nStrandOverlap / 100 * LayerParams.dStrand) -- riordino le curve appena create e se possibile creo percorsi chiusi ReorderExtraShells( nGrpId, LayerParams.dStrand, vPtStart, LayerParams.bPrintInvert) end -------------------------------------------------------------------- ------------------ AUX SOLIDS ------------------------------------- -------------------------------------------------------------------- local function UpdateTrimSurfWithAuxSolidsOffset( nSrfSolid, nSrfBase, dStrand, nCrvGrp, vtSlicing) -- offset della superifice del solido local bOk, bExists, nSrfOffs = ComputeSurfOffset( nSrfSolid, nCrvGrp, dStrand, vtSlicing) if nSrfOffs then EgtSurfFrSubtract( nSrfBase, nSrfOffs) EgtErase( nSrfOffs) end end -------------------------------------------------------------------- local function UpdateTrimSurfWithAuxSolidsZigZag( nAuxSolidsGrp, sName, nSrfBase, dStrand, nSrf) local nGrpTmp = EgtGroup( nAuxSolidsGrp) -- gruppo temporaneo per conti -- recupero le curve associate local vCrvs = EgtGetNameInGroup( nAuxSolidsGrp, sName) for i = 1, #vCrvs do local vtDir = EgtSV( vCrvs[i]) -- costruisco percorso associato local nCopyCrv = EgtCopyGlob( vCrvs[i], nGrpTmp) local nCopy2 = EgtCopyGlob( vCrvs[i], nGrpTmp) EgtInvertCurve( nCopy2) EgtAddCurveCompoCurve( nCopyCrv, nCopy2) local nOffsP = EgtOffsetCurveAdv( nCopyCrv, dStrand, GDB_OT.FILLET) local nFirst, nCnt = EgtExplodeCurveCompo( nOffsP, nGrpTmp) -- cerco tratti lineari orientati ortogonalmente alla direzione di svuotatura local nRes = EgtCurveCompo( nGrpTmp, {nFirst}) local nInd = nFirst + 1 while nInd < nFirst + nCnt do local vtCurrDir = EgtSV( nInd) local nType = EgtGetType( nInd) -- se è linea ortognale alla direzione della svuotatura la approssimo if nType == GDB_TY.CRV_LINE and abs( vtDir * vtCurrDir) < 10 * GEO.EPS_SMALL then -- cerco ultima curva con lo stesso orientamento local nLastValidId = nInd local nInd2 = nInd + 1 while nInd2 < nFirst + nCnt do nType = EgtGetType( nInd2) if nType == GDB_TY.CRV_LINE then if AreSameVectorApprox( EgtSV( nInd2), vtCurrDir) then nLastValidId = nInd2 else break end end nInd2 = nInd2 + 1 end -- aggiungo l'approssimazione lineare EgtAddCurveCompoLine( nRes, EgtEP( nLastValidId)) -- setto l'indice per ripartire correttamente dopo l'approssimazione nInd = nLastValidId else -- se arco o linea inclinata, aggiungo direttamente al percorso EgtAddCurveCompoCurve( nRes, nInd) end nInd = nInd + 1 end -- utilizzo la curva per creare superficie local nSrfZigZag = EgtSurfFlatRegion( nGrpTmp, {nRes}) if nSrfZigZag then EgtSurfFrSubtract( nSrfBase, nSrfZigZag) else EgtSurfFrSubtract( nSrfBase, nSrf) end end EgtErase( nGrpTmp) end ------------------------------------------------------------------- local function AddExtraZigZag( nSrf, sName, dStrand, vtSlicing, nGrp, nSrfTrim) local vIds = EgtGetNameInGroup( nGrp, sName) local vtDir = EgtSV( vIds[1], GDB_ID.ROOT) local vtYLoc = vtSlicing ^ vtDir local nOuterLoop = EgtExtractSurfFrChunkLoops( nSrf, 0, nGrp) for i = 1, #vIds do local _, dParE = EgtCurveDomain( vIds[i]) local ptS = EgtUP( vIds[i], dParE - 1, GDB_ID.ROOT) + dStrand * vtYLoc local ptE = EgtEP( vIds[i], GDB_ID.ROOT) + dStrand * vtYLoc local nExtraCrv = EgtLine( nGrp, ptS, ptE, GDB_RT.GLOB) -- verifico se la linea aggiuntiva serve local dDist = EgtPointCurveDist( EgtMP( nExtraCrv), nOuterLoop) if dDist < dStrand - 1 then -- verifico se si trova nella regione ammissibile if EgtCurveWithRegionClassify( nExtraCrv, nSrfTrim) == GDB_CRC.IN then EgtInvertCurve( nExtraCrv) EgtAddCurveCompoLine( vIds[i], ptE, GDB_RT.GLOB) EgtAddCurveCompoCurve( vIds[i], nExtraCrv) end end EgtErase( nExtraCrv) end EgtErase( nOuterLoop) end -------------------------------------------------------------------- local function CalcAuxSolidsPaths( nSliceGrp, nSolidGrp, LayerParams, vPtStart) -- recupero i solidi ausiliari local vSolidIds = EgtGetAllInGroup( nSolidGrp) -- scorro i gruppi di curve local nCrvGrp = EgtGetFirstNameInGroup( nSliceGrp, CONTOUR_GRP .. '*') while nCrvGrp do -- creo o svuoto il gruppo per i solidi ausiliari local nSolidPathGrp = EgtGetFirstNameInGroup( nCrvGrp, AUX_SOLIDS_GRP) if not nSolidPathGrp then nSolidPathGrp = EgtGroup( nCrvGrp) EgtSetName( nSolidPathGrp, AUX_SOLIDS_GRP) EgtSetStatus( nSolidPathGrp, GDB_ST.OFF) else EgtEmptyGroup( nSolidPathGrp) end -- creo le superfici con cui fare i trim local nSrfBase = EgtGetFirstNameInGroup( nCrvGrp, TOT_SHELL_TRIM_SURF) if not nSrfBase then EgtOutLog( 'Warning : AuxSolids not possible (layer '..tostring( nIdx)..') - CalcPaths') else local vSurfOffs = ComputeTrimSurfWithOverlaps( vSolidIds, nSrfBase, KEY_AUX_SOLIDS_OVERLAP, LayerParams.dStrand, nSolidPathGrp, LayerParams.vtSlicing) for i = 1, #vSolidIds do -- creo la flat region corrispondente al solido ausiliario local sName = EgtGetName( vSolidIds[i]) local nOverlap = EgtGetInfo( vSolidIds[i], KEY_AUX_SOLIDS_OVERLAP, 'i') local nSrfId = EgtSurfFlatRegion( nSolidPathGrp, vSolidIds[i]) EgtSetName( nSrfId, AUX_SOLIDS_SRF) -- trim con la superficie di offset EgtSurfFrIntersect( nSrfId, vSurfOffs[nOverlap]) local nFirst, nCnt = EgtExplodeSurf( nSrfId) for j = 0, nCnt - 1 do local sNewName = sName .. EgtIf( j == 0, '', '_' .. tostring( j)) local nInfillType = EgtGetInfo( vSolidIds[i], KEY_AUX_SOLIDS_INFILL, 'i') if nInfillType == INFILL_TYPE.OFFSET then ComputeOffsetInfill( nFirst + j, LayerParams.dStrand, LayerParams.vtSlicing, sNewName, TYPE.AUX_SOLID, vPtStart, nSolidPathGrp) -- aggiorno la trim surf UpdateTrimSurfWithAuxSolidsOffset( nFirst + j, nSrfBase, LayerParams.dStrand, nSolidPathGrp, LayerParams.vtSlicing) else ComputeZigZagInfill( nFirst + j, LayerParams.dStrand, LayerParams.vtSlicing, sNewName, TYPE.AUX_SOLID, vPtStart, nSolidPathGrp) -- aggiungo eventuale passata extra AddExtraZigZag( nFirst + j, sNewName, LayerParams.dStrand, LayerParams.vtSlicing, nSolidPathGrp, vSurfOffs[nOverlap]) -- aggiorno la trim surf UpdateTrimSurfWithAuxSolidsZigZag( nSolidPathGrp, sNewName, nSrfBase, LayerParams.dStrand, nFirst + j) end end end -- elimino le superfici utilizzate per il trim for k, v in pairs( vSurfOffs) do EgtErase( v) end end -- verifico se il gruppo contine qualcosa if not EgtGetFirstNameInGroup( nSolidPathGrp, AUX_SOLIDS_CRV .. '*') then EgtErase( nSolidPathGrp) end -- passo al gruppo di contorni successivo nCrvGrp = EgtGetNextName( nCrvGrp, CONTOUR_GRP .. '*') end end --------------------------------------------------------------------- function CalcPaths.Exec( nPartId) s_nPartId = nPartId local vLayIds = EgtGetNameInGroup( s_nPartId, SLICE_LAYER.."*") if not vLayIds then EgtOutBox( 'Error no slice', 'PathCalc') return true end -- recupero i parametri per calcolo dei path local LayerParams = GetLayerParamsForPathCalc() -- scorro tutti i suoi layer for nIdx = 1, #vLayIds do local nRibsGrp = EgtGetFirstNameInGroup( vLayIds[nIdx], RIBS_GRP) local nAuxSolidsGrp = EgtGetFirstNameInGroup( vLayIds[nIdx], AUX_SOLIDS_GRP) -- regioni con diverso numero di passate local nShellNbrGrp = EgtGetFirstNameInGroup( vLayIds[nIdx], SHELL_NBR_GRP) local nMaxShell = max( LayerParams.nShellsNbr, LayerParams.nFloorNbr, LayerParams.nCeilNbr) CreateShellNbrSurfaces( nShellNbrGrp, nMaxShell) local nShellNbrSurfGrp = EgtGetFirstGroupInGroup( nShellNbrGrp or GDB_ID.NULL) -- recupero gli start point per il layer local vPtStart = GetLayerStartPoint( vLayIds[nIdx], LayerParams.vtSlicing) -- scorro tutti i gruppi di contorni local nCrvGrpId = EgtGetFirstNameInGroup( vLayIds[nIdx], CONTOUR_GRP.."*") or GDB_ID.NULL while nCrvGrpId ~= GDB_ID.NULL do -- verifico se il path è già stato calcolato local nGrpId = EgtGetFirstNameInGroup( nCrvGrpId, PATH_GRP) or GDB_ID.NULL if nGrpId == GDB_ID.NULL then nGrpId = EgtGroup( nCrvGrpId) EgtSetName( nGrpId, PATH_GRP) else EgtEmptyGroup( nGrpId) EgtSetStatus( nGrpId, GDB_ST.ON) end -- recupero la superficie ottenuta dallo slicing local nSrf = EgtGetFirstNameInGroup( nCrvGrpId, LAYER_SRF) if nSrf then local nMaxShellNbrDiff = ComputeMaxShellNbrDiff( nSrf, nShellNbrSurfGrp) nMaxShellNbrDiff = min( nMaxShellNbrDiff, LayerParams.nShellsNbr) -- parete esterna local dOffs = - LayerParams.dOffs - 0.5 * LayerParams.dStrand if nMaxShellNbrDiff < LayerParams.nShellsNbr then dOffs = dOffs + LayerParams.dStrand local bOk, bExists, nSrfId = ComputeSurfOffset( nSrf, nCrvGrpId, - dOffs, LayerParams.vtSlicing) if not bOk then EgtOutLog( 'Error on ExtOffset (layer '..tostring( nIdx)..') - CalcPaths') elseif not bExists then EgtOutLog( 'Warning : ExtOffset not possible (layer '..tostring( nIdx)..') - CalcPaths') else -- se offset riuscito, estraggo i contorni (pareti esterne) GetPathsFromSurf( nSrfId, SHELL_CRV ..'0', TYPE.OUTER_SHELL, nGrpId, vPtStart) end EgtErase( nSrfId) end local vPtInnerStart = {} local vOuterShell = EgtGetNameInGroup( nGrpId, SHELL_CRV .. '0') or {} for i = 1, #vOuterShell do table.insert( vPtInnerStart, EgtSP( vOuterShell[i])) end if #vPtInnerStart == 0 then vPtInnerStart = vPtStart end EgtSetInfo( nCrvGrpId, KEY_START_POINT, vPtInnerStart[1]) -- pareti interne complete for nInd = 1, LayerParams.nShellsNbr - 1 - nMaxShellNbrDiff do -- offset della superficie originale dOffs = dOffs + LayerParams.dStrand * ( 1 - LayerParams.nStrandOverlap / 100) local bOk, bExists, nSrfId = ComputeSurfOffset( nSrf, nCrvGrpId, - dOffs, LayerParams.vtSlicing) if not bOk then EgtOutLog( 'Error on IntOffset (layer '..tostring( nIdx)..') - CalcPaths') elseif not bExists then EgtOutLog( 'Warning : IntOffset not possible (layer '..tostring( nIdx)..') - CalcPaths') else -- se offset riuscito, estraggo i contorni ( pareti interne) GetPathsFromSurf( nSrfId, SHELL_CRV..tostring( nInd), TYPE.INNER_SHELL, nGrpId, vPtInnerStart) end EgtErase( nSrfId) end -- preparo superficie occupata dalle shell da usare per trim local dSurfTrimOffs = dOffs + LayerParams.dStrand if nMaxShellNbrDiff > 0 then -- se hai extra shell tieni conto anche dell'overlap ammesso dSurfTrimOffs = dOffs + ( 1 - LayerParams.nStrandOverlap / 100) * LayerParams.dStrand - s_dOffsCorr end local bOkTrim, bExistsTrim, nSrfTrim = ComputeSurfOffset( nSrf, nCrvGrpId, - dSurfTrimOffs, LayerParams.vtSlicing) if not bOkTrim then EgtOutLog( 'Error on IntOffset (layer '..tostring( nIdx)..') - CalcPaths') elseif bExistsTrim then EgtSetName( nSrfTrim, TOT_SHELL_TRIM_SURF) EgtSetStatus( nSrfTrim, GDB_ST.OFF) end -- eventuali pareti interne coinvolte dal diverso numero di passate if nMaxShellNbrDiff > 0 then CalcExtraShellsPath( nMaxShellNbrDiff, nShellNbrSurfGrp, nCrvGrpId, dOffs, LayerParams, nIdx, vPtInnerStart) end -- gestione eventuale floor/ceil if nIdx <= LayerParams.nFloorNbr then local nSurfInfill = AdjustSurfForFloorCeil( LayerParams.nFloorNbr - nIdx + 1, nSrfTrim, nShellNbrSurfGrp) or nSrfTrim if LayerParams.nFloorType == INFILL_TYPE.OFFSET then ComputeOffsetInfill( nSurfInfill, LayerParams.dStrand, LayerParams.vtSlicing, INFILL_CRV, TYPE.INFILL, vPtStart, nGrpId) elseif LayerParams.nFloorType == INFILL_TYPE.ZIGZAG then ComputeZigZagInfill( nSurfInfill, LayerParams.dStrand, LayerParams.vtSlicing, INFILL_CRV, TYPE.INFILL, vPtStart, nGrpId) end EgtErase( nSurfInfill) elseif nIdx > #vLayIds - LayerParams.nCeilNbr then local nSurfInfill = AdjustSurfForFloorCeil( LayerParams.nCeilNbr - ( #vLayIds - nIdx), nSrfTrim, nShellNbrSurfGrp) or nSrfTrim if LayerParams.nCeilType == INFILL_TYPE.OFFSET then ComputeOffsetInfill( nSurfInfill, LayerParams.dStrand, LayerParams.vtSlicing, INFILL_CRV, TYPE.INFILL, vPtStart, nGrpId) elseif LayerParams.nCeilType == INFILL_TYPE.ZIGZAG then ComputeZigZagInfill( nSurfInfill, LayerParams.dStrand, LayerParams.vtSlicing, INFILL_CRV, TYPE.INFILL, vPtStart, nGrpId) end EgtErase( nSurfInfill) end end -- passo al gruppo di contorni successivo nCrvGrpId = EgtGetNextName( nCrvGrpId, CONTOUR_GRP.."*") or GDB_ID.NULL end if nIdx > LayerParams.nFloorNbr and nIdx <= #vLayIds - LayerParams.nCeilNbr then -- sistemo eventuali solidi ausiliari if nAuxSolidsGrp then CalcAuxSolidsPaths( vLayIds[nIdx], nAuxSolidsGrp, LayerParams, vPtStart) end -- sistemo eventuali costolature if nRibsGrp then CalcRibsPaths( vLayIds[nIdx], nRibsGrp, LayerParams, nIdx, vPtStart) end end if EgtProcessEvents( EgtIf( PRINT, 200, 0) + nIdx / #vLayIds * 100, 0) == 1 then EgtDraw() return false end end return true end --------------------------------------------------------------------- return CalcPaths