-- 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 = 50 * GEO.EPS_SMALL --------------------------------------------------------------------- local function GetLayerParamsForPathCalc() local LayerParams = {} LayerParams.nShellsNbr = EgtGetInfo( s_nPartId, KEY_SHELLS_NBR, 'i') LayerParams.dStrand = EgtGetInfo( s_nPartId, KEY_STRAND, 'd') LayerParams.dOffs = EgtGetInfo( s_nPartId, KEY_OFFSET_SLICE, 'd') LayerParams.nFloorNbr = EgtGetInfo( s_nPartId, KEY_FLOOR_NBR, 'i') LayerParams.vtSlicing = EgtGetInfo( s_nPartId, KEY_SLICING_DIR, 'v') LayerParams.bPrintInvert = ( EgtGetInfo( s_nPartId, KEY_PRINT_DIRECTION, 'i') == PRINT_DIRECTION.CW) -- parametri costolature LayerParams.bRibsInvertOrder = EgtGetInfo( s_nPartId, KEY_RIBS_INVERT_ORDER, 'b') return LayerParams end ---------------------------------------------------------------------- local function ComputeSurfOffset( nSrf, nGrpId, dOffs) local nCopySrf = EgtCopy( nSrf, nGrpId) local bOk = EgtSurfFrOffset( nCopySrf, dOffs) local bExists = EgtSurfFrChunkCount( nCopySrf) > 0 if not bOk or not bExists then EgtErase( nCopySrf) nCopySrf = EgtCopyGlob( nSrf, nGrpId) bOk = EgtSurfFrOffset( nCopySrf, dOffs + 0.05) bExists = EgtSurfFrChunkCount( nCopySrf) > 0 end 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 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 EgtChangeClosedCurveStartPoint( nCrvId, vPtStart[nMinIdx]) else -- se non ci sono start point disponibili prendo l'origine EgtChangeClosedCurveStartPoint( nCrvId, Point3d( 0, 0, 0), GDB_RT.GLOB) end end --------------------------------------------------------------------- local function GetPathsFromSurf( nSrfId, sName, nType, nGrpId, vPtStart) 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 ModifyStartPoint( nCrvId + nInd, vPtStart) end end end -------------------------------------------------------------------- local function AddFloor( nSrfId, nGrpId, LayerParams, nFloorNbr) -- local nSrfCopy = EgtCopyGlob( nSrfId, nGrpId) -- local dOffs = 0.5 * LayerParams.dStrand - LayerParams.dOffs + LayerParams.nShellsNbr * LayerParams.dStrand -- local dAng = 0 -- -- if EgtSurfFrOffset( nSrfCopy, - dOffs) and EgtSurfFrChunkCount( nSrfCopy) > 0 then -- local nCrvId, nCnt = EgtGetSurfFrZigZagInfill( nSrfCopy, nGrpId, LayerParams.dStrand + 10 * GEO.EPS_SMALL, dAng, false, false) -- for nInd = 0, nCnt - 1 do -- local dLen = EgtCurveLength( nCrvId + nInd) -- if dLen < MIN_LEN then -- EgtErase( nCrvId + nInd) -- else -- EgtSetName( nCrvId + nInd, INFILL_CRV) -- EgtSetInfo( nCrvId + nInd, KEY_TYPE, TYPE.INFILL) -- end -- end -- EgtErase( nSrfCopy) -- end end ------------------------------------------------------------------- --------------------------- RIBS ----------------------------------- -------------------------------------------------------------------- -------------------------------------------------------------------- local function TrimRibsOffset( nCrv, nOffs1, nOffs2, nOffsGrp, bIn) local ptInt1 = EgtIP( nCrv, nOffs1, ORIG()) local ptInt2 = EgtIP( nCrv, nOffs2, ORIG()) local dPar1, dPar2 if ptInt1 then dPar1 = EgtCurveParamAtPoint( nCrv, ptInt1) end if ptInt2 then dPar2 = EgtCurveParamAtPoint( nCrv, ptInt2) end if dPar1 and dPar2 then -- la curva viene spezzata in tre parti if dPar1 > dPar2 then dPar1, dPar2 = dPar2, dPar1 end local nCopy = EgtCopyGlob( nCrv, nOffsGrp) EgtTrimCurveEndAtParam( nCrv, dPar1) EgtTrimCurveStartAtParam( nCopy, dPar2) EgtSetInfo( nCopy, KEY_SPLIT_RIB, nCrv) elseif dPar1 or dPar2 then if bIn then EgtTrimCurveEndAtParam( nCrv, dPar1 or dPar2) else EgtTrimCurveStartAtParam( nCrv, dPar1 or dPar2) end end end -------------------------------------------------------------------- -- Funzione che sistema le intersezioni fra costolature nel caso generico local function AdjustRibsOffsetForIntersection( nCrv1, nCrv2, LayerParams, nOffsGrp, bIn) -- calcolo gli offset della curva principale ( nCrv1) da usare per trim local nShells = EgtGetInfo( nCrv1, KEY_RIBS_SHELLS_NBR, 'i') local nOverlap1 = EgtGetInfo( nCrv1, KEY_RIBS_OVERLAP, 'i') local nOverlap2 = EgtGetInfo( nCrv2, KEY_RIBS_OVERLAP, 'i') local nOverlap = min( nOverlap1, nOverlap2) local dOffs = ( nShells - 1) * LayerParams.dStrand / 2 local nOffsM = EgtOffsetCurveAdv( nCrv1, - dOffs - ( 1 - nOverlap / 100) * LayerParams.dStrand) local nOffsP = EgtOffsetCurveAdv( nCrv1, dOffs + ( 1 - nOverlap / 100) * LayerParams.dStrand) local vSplit = {} -- recupero gli offset della curva secondaria ( nCrv2) local vOffs2 = EgtGetNameInGroup( nOffsGrp, EgtGetName( nCrv2)) -- trim degli offset della curva secondaria for i = 1, #vOffs2 do TrimRibsOffset( vOffs2[i], nOffsM, nOffsP, nOffsGrp, bIn) end EgtErase( nOffsM) EgtErase( nOffsP) end -------------------------------------------------------------------- -- Funzione che sistema le intersezioni fra costolature nel caso di 2 passate local function AdjustRibsOffsetForIntersection2Shells( nCrv1, nCrv2, LayerParams, nOffsGrp, bIn) -- recupero gli offset delle due curve local vOffs1 = EgtGetNameInGroup( nOffsGrp, EgtGetName( nCrv1)) local vOffs2 = EgtGetNameInGroup( nOffsGrp, EgtGetName( nCrv2)) local vCopy1 = {} for i = 1, #vOffs1 do local nId = EgtCopyGlob( vOffs1[i], nOffsGrp) table.insert( vCopy1, nId) end -- trim degli offset di nCrv1 for i = 1, #vOffs1 do -- trovo gli offset di nCrv2 coinvolti nell'intersezione local vIds = {} for j = 1, #vOffs2 do local ptInt = EgtIP( vOffs1[i], vOffs2[j], ORIG()) if ptInt then table.insert( vIds, j) end end if #vIds > 0 then local bInCrv1 = false -- se viene trovata una sola intersezione devo calcolare bIn per nCrv1 if #vIds == 1 then table.insert( vIds, EgtIf( vIds[1] == 1, 2, 1)) local ptInt = EgtIP( nCrv1, nCrv2, ORIG()) local dParInt = EgtCurveParamAtPoint( nCrv1, ptInt) local _, dParE = EgtCurveDomain( nCrv1) bInCrv1 = abs( dParInt - dParE) < 100 * GEO.EPS_SMALL end TrimRibsOffset( vOffs1[i], vOffs2[vIds[1]], vOffs2[vIds[2]], nOffsGrp, bInCrv1) end end -- trim degli offset di nCrv2 for i = 1, #vOffs2 do -- trovo gli offset di nCrv1 coinvolti nell'intersezione local vIds = {} for j = 1, #vCopy1 do local ptInt = EgtIP( vOffs2[i], vCopy1[j], ORIG()) if ptInt then table.insert( vIds, j) end end if #vIds > 0 then if #vIds == 1 then table.insert( vIds, EgtIf( vIds[1] == 1, 2, 1)) end TrimRibsOffset( vOffs2[i], vCopy1[vIds[1]], vCopy1[vIds[2]], nOffsGrp, bIn) end end for i = 1, #vCopy1 do EgtErase( vCopy1[i]) end end -------------------------------------------------------------------- local function HandleRibsIntersections( nRibsGrp, LayerParams, nOffsGrp, nRibsPathGrp, bAllTwoStrands) local nCrvGrp = EgtGetParent( nRibsPathGrp) local nSrf = EgtGetFirstInGroup( nCrvGrp) local vRibsIds = {} local vOrigRibs = EgtGetNameInGroup( nRibsGrp, RIBS_CRV .. '*') local nTrimmedRibsGrp = EgtGroup( nRibsPathGrp) for i = 1, #vOrigRibs do local nCopyId = EgtCopyGlob( vOrigRibs[i], nTrimmedRibsGrp) local nCrv, nCnt = EgtTrimCurveWithRegion( nCopyId, nSrf, true, false) for j = nCrv, nCrv + nCnt - 1 do table.insert( vRibsIds, j) end -- copio i suoi offset nel RibsPathGrp local vOffsRib = EgtGetNameInGroup( nOffsGrp, EgtGetName( vOrigRibs[i])) for i = 1, #vOffsRib do EgtCopyGlob( vOffsRib[i], nRibsPathGrp) end end local bInters = false local vSplit = {} for i = 1, #vRibsIds do -- verifico se interseca uno dei setti successivi for j = i + 1, #vRibsIds do local ptInt = EgtIP( vRibsIds[i], vRibsIds[j], ORIG()) if ptInt then bInters = true local dPar1 = EgtCurveParamAtPoint( vRibsIds[i], ptInt) local dPar2 = EgtCurveParamAtPoint( vRibsIds[j], ptInt) local _, dParE1 = EgtCurveDomain( vRibsIds[i]) local _, dParE2 = EgtCurveDomain( vRibsIds[j]) local bIn = abs( dPar1 - dParE1) < 50 * GEO.EPS_SMALL or abs( dPar2 - dParE2) < 50 * GEO.EPS_SMALL local nCrv1 = vRibsIds[i] -- curva principale che non viene tagliata local nCrv2 = vRibsIds[j] -- curve secondaria da modificare if dPar1 < 50 * GEO.EPS_SMALL or abs( dPar1 - dParE1) < 50 * GEO.EPS_SMALL then nCrv1, nCrv2 = nCrv2, nCrv1 end if bAllTwoStrands then -- nel caso di 2 passate gestione speciale AdjustRibsOffsetForIntersection2Shells( nCrv1, nCrv2, LayerParams, nRibsPathGrp, bIn) else AdjustRibsOffsetForIntersection( nCrv1, nCrv2, LayerParams, nRibsPathGrp, bIn) end end end end EgtErase( nTrimmedRibsGrp) return bInters end -------------------------------------------------------------------- -- Funzione che riordina le costolature nel caso generico local function ReorderRibs( nGrp, bInvertOrder, dStrand, nMaxNbr) EgtSpInit() local vIds = EgtGetNameInGroup( nGrp, RIBS_CRV .. '*') if not vIds or #vIds == 0 then return end local vSplitRibs = {} local vSPRibs = {} for i = 1, #vIds do local nInfo = EgtGetInfo( vIds[i], KEY_SPLIT_RIB, 'i') local nShells = EgtGetInfo( vIds[i], KEY_RIBS_SHELLS_NBR, 'i') -- se è ottenuto dalla divisione di una costolatura non va considerato per il TSP ( viene aggiunto in seguito) if nInfo and nShells == 1 then table.insert( vSplitRibs, vIds[i]) else local pt = EgtMP( vIds[i], GDB_RT.GLOB) EgtSpAddPoint( pt:getX(), pt:getY(), pt:getZ(), 0, 0, pt:getX(), pt:getY(), pt:getZ(), 0, 0) table.insert( vSPRibs, vIds[i]) end end local vOrd, dLen = EgtSpCalculate( SHP_TY.OPEN) EgtSpTerminate() EgtRelocateGlob( vSPRibs[vOrd[1]], nGrp, EgtIf( bInvertOrder, GDB_IN.LAST, GDB_IN.FIRST)) for i = 2, #vOrd do EgtRelocateGlob( vSPRibs[vOrd[i]], vSPRibs[vOrd[i-1]], EgtIf( bInvertOrder, GDB_IN.BEFORE, GDB_IN.AFTER)) end -- aggiusto tutte le costolature divise for i = 1, #vSplitRibs do local nPrevId = EgtGetInfo( vSplitRibs[i], KEY_SPLIT_RIB, 'i') -- aggiungo come successiva alla costolatura da cui si è generata EgtRelocateGlob( vSplitRibs[i], nPrevId, GDB_IN.AFTER) end -- sistemo nomi local kMax = nMaxNbr + 1 for i = 1, nMaxNbr do local vIds = EgtGetNameInGroup( nGrp, RIBS_CRV .. tostring(i)) or {} for j = 2, #vIds do local ptM = EgtMP( vIds[j]) local dDist = EgtPointCurveDist( ptM, vIds[j-1]) if abs( dDist - dStrand) < 20 * GEO.EPS_SMALL then -- se le costolatura è vicina alla precedente avrà lo stesso nome EgtSetName( vIds[j], EgtGetName( vIds[j-1])) EgtRelocateGlob( vIds[j], vIds[j-1], GDB_IN.AFTER) else -- se la costolatura dista troppo dalla precedente le cambio il nome EgtSetName( vIds[j], RIBS_CRV .. tostring( kMax)) kMax = kMax + 1 end end end end -------------------------------------------------------------------------------------------- local function CopyInfo( nSouId, nDestId, sInfo, sType) local info = EgtGetInfo( nSouId, sInfo, sType) EgtSetInfo( nDestId, sInfo, info) end -------------------------------------------------------------------------------------------- local function ReassignInfo( nCrv, nCnt, vOrig) for nId = nCrv, nCrv + nCnt - 1 do local ptS = EgtSP( nId) local ptE = EgtEP( nId) -- info overlap local nOverlap = EgtGetInfo( s_nPartId, KEY_RIBS_OVERLAP, 'i') EgtSetInfo( nId, KEY_RIBS_OVERLAP, nOverlap) 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') 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) local vOffs = EgtGetNameInGroup( nOffsGrp, RIBS_CRV .. '*') -- 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 EgtSetInfo( i, KEY_TYPE, TYPE.RIB) table.insert( vIds, i) end 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, 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 bFound = false for j = 1, #vIds do if vIds[j] ~= nCrv and not EgtCurveIsClosed(vIds[j]) 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 then nCurrCrv = nil end end end -- Recupero le info dalle curve originali ReassignInfo( nCrv, nCnt, vCopy) end -------------------------------------------------------------------- local function CalcRibsPaths( nSliceGrp, nRibsGrp, LayerParams, nIdx, nMaxStrandDiff) local vRibs = EgtGetNameInGroup( nRibsGrp, RIBS_CRV .. '*') -- verifico se tutte le costolature vengono fatte con 2 passate local bAllTwoStrands = true for i = 1, #vRibs do local nStrand = EgtGetInfo( vRibs[i], KEY_RIBS_SHELLS_NBR, 'i') if nStrand ~= 2 then bAllTwoStrands = false break end end local nLast = EgtGetLastNameInGroup( nRibsGrp, RIBS_CRV .. '*') local sLastName = EgtGetName( nLast) local nMaxNbr = tonumber( string.sub( sLastName, 4)) -- calcolo gli offset local nOffsGrp = EgtGroup( nRibsGrp) for i = 1, #vRibs do local nShellsNbr = EgtGetInfo( vRibs[i], KEY_RIBS_SHELLS_NBR, 'i') local dOffs = ( nShellsNbr - 1) * LayerParams.dStrand / 2 for k = 0, nShellsNbr - 1 do local nNewId = EgtOffsetCurveAdv( vRibs[i], - dOffs + k * LayerParams.dStrand) EgtSetName( nNewId, EgtGetName( vRibs[i])) EgtSetInfo( nNewId, KEY_TYPE, TYPE.RIB) EgtRelocateGlob( nNewId, nOffsGrp) end end -- scorro i gruppi di curve local dOffs = 0.5 * LayerParams.dStrand - LayerParams.dOffs + ( LayerParams.nShellsNbr - 1) * LayerParams.dStrand 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 -- creo le superfici con cui fare i trim local nSrfBase = EgtGetFirstNameInGroup( nCrvGrp, TOT_SHELL_TRIM_SURF) if not nSrfBase then EgtOutLog( 'Warning : Ribs not possible (layer '..tostring( nIdx)..') - CalcPaths') else local vSurfOffs = {} for i = 1, #vRibs do local nOverlap = EgtGetInfo( vRibs[i], KEY_RIBS_OVERLAP, 'i') if not vSurfOffs[nOverlap] then local dNewOffs = nOverlap / 100 * LayerParams.dStrand local bOk, bExists, nSrfOffs = ComputeSurfOffset( nSrfBase, nRibsPathGrp, dNewOffs) if bOk then vSurfOffs[nOverlap] = nSrfOffs end end end -- gestisco eventuali intersezioni fra costolature local bInters = HandleRibsIntersections( nRibsGrp, LayerParams, nOffsGrp, nRibsPathGrp, bAllTwoStrands) EgtSetInfo( nRibsPathGrp or GDB_ID.NULL, KEY_RIBS_INTERS, bInters) EgtSetInfo( nRibsPathGrp or GDB_ID.NULL, KEY_RIBS_TWO_STRANDS, bAllTwoStrands) -- eseguo il trim delle costole con la regione offsettata local tOldNewIds = {} local vOrderedRibs = EgtGetNameInGroup( nRibsPathGrp, RIBS_CRV ..'*') for i = 1, #vOrderedRibs do -- trim con superficie opportuna local nOverlap = EgtGetInfo( vOrderedRibs[i], KEY_RIBS_OVERLAP, 'i') if not vSurfOffs[ nOverlap] then -- la costolatura non è fattibile EgtOutLog( 'Warning: Ribs not possibile (layer '..tostring( nIdx)..') - CalcPaths') EgtErase( vOrderedRibs[i]) else local nCrv, nCnt = EgtTrimCurveWithRegion( vOrderedRibs[i], vSurfOffs[nOverlap], true, false) tOldNewIds[ vOrderedRibs[i]] = {} -- elimino tratti troppo corti for nInd = 0, nCnt - 1 do local dLen = EgtCurveLength( nCrv + nInd) if dLen < 10 * MIN_LEN then EgtErase( nCrv + nInd) else table.insert( tOldNewIds[ vOrderedRibs[i]], nCrv + nInd) -- controllo la direzione local vtDir = EgtMV( nCrv + nInd) local dVal = EgtIf( abs( vtDir:getX()) > abs( vtDir:getY()) - GEO.EPS_SMALL, vtDir:getX(), vtDir:getY()) if dVal < - GEO.EPS_SMALL then EgtInvertCurve( nCrv + nInd) end if nInd == 0 then -- aggiorno la info local nInfo = EgtGetInfo( nCrv + nInd, KEY_SPLIT_RIB, 'i') if nInfo then -- aggiorno info if #tOldNewIds[nInfo] > 0 then local nLast = #tOldNewIds[nInfo] EgtSetInfo( nCrv + nInd, KEY_SPLIT_RIB, tOldNewIds[nInfo][nLast]) else -- se la costolatura da cui deriva è stata eliminata, tolgo l'info che le associava EgtRemoveInfo( nCrv + nInd, KEY_SPLIT_RIB) end end end end end end end -- riordino le costolature if bAllTwoStrands and bInters then -- gestione caso speciale di intersezione e 2 passate ReorderRibsInters2Shells( nRibsPathGrp, LayerParams.dStrand) else ReorderRibs( nRibsPathGrp, LayerParams.bRibsInvertOrder, LayerParams.dStrand, nMaxNbr) end end if not EgtGetFirstNameInGroup( nRibsPathGrp, RIBS_CRV .. '*') then EgtErase( nRibsPathGrp) 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 -- 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 nCrvId = EgtGetNextName( nCrvId, SHELL_NBR_CRV .. '*') end -- eventuale correzione del numero massimo in base al numero di pareti interne nMaxShellNbrDiff = min( nMaxShellNbrDiff, nShellsNbr - 1) -- 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, nCnt = EgtSurfFlatRegion( nSrfGrp, vCrvIds) for nIdSrf = nSrfId + 1, nSrfId + nCnt - 1 do EgtSurfFrAdd( nSrfId, nIdSrf) end EgtSetName( nSrfId, SHELL_NBR_SURF .. tostring( nDiff)) 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 UpdateTotalShellSurf( nSrf, nCrv, dStrand, nGrpId) local nCopyCrv = EgtCopyGlob( nCrv, nGrpId) -- creo percorso chiuso corrispondente if not EgtCurveIsClosed( nCrv) then local nCopy2 = EgtCopyGlob( nCrv, nGrpId) EgtInvertCurve( nCopy2) EgtAddCurveCompoCurve( nCopyCrv, nCopy2) end local nOffsP = EgtOffsetCurveAdv( nCopyCrv, dStrand - s_dOffsCorr, GDB_OT.EXTEND) local vSrfIds = { nOffsP} if EgtCurveIsClosed( nCrv) then -- se curva è chiusa bisogna tenere conto dell'interno local nOffsM, nCnt = EgtOffsetCurveAdv( nCopyCrv, - dStrand + s_dOffsCorr) if nOffsM and nOffsM ~= GDB_ID.NULL then for nId = nOffsM, nOffsM + nCnt - 1 do table.insert( vSrfIds, nId) end end end local nSrfExtraShell = EgtSurfFlatRegion( nGrpId, vSrfIds) if not EgtSurfFrSubtract( nSrf, nSrfExtraShell) then EgtInvertSurf( nSrfExtraShell) EgtSurfFrSubtract( nSrf, nSrfExtraShell) end EgtErase( nCopyCrv) for i = 1, #vSrfIds do EgtErase( vSrfIds[i]) end EgtErase( nSrfExtraShell) end --------------------------------------------------------------------- local function ReorderExtraShells( nPathGrp, dStrand, vPtStart, bPrintInvert) 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]) EgtSetInfo( vIds[i], KEY_INVERTED_CURVE, 1) 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) EgtSetInfo( nCurrCrv, KEY_CLOSED_EXTRA_SHELL, 1) -- 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]) if nCnt == 0 and dist( ptE, ptSCurr) < 1.5 * dStrand and EgtGetName( nCurrCrv) == EgtGetName( vIds[j]) then nCnt = nCnt + 1 EgtRelocateGlob( vIds[j], nCurrCrv, GDB_IN.BEFORE) EgtSetName( vIds[j], EXTRA_SHELL_CRV .. tostring( k)) table.remove( vIds, j) bFound = true break end 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_CURVE, 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_CURVE, 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 VerifyExtraShellPath( nCrv, nGrpId, vtSlicing, dStrand) -- verifico se è fattibile controllando se esiste offset local nOffs, nCnt = EgtOffsetCurveAdv( nCrv, - 0.5 * dStrand) if not nOffs or nOffs == GDB_ID.NULL then return false end for i = nOffs, nOffs + nCnt - 1 do EgtErase( i) end -- controllo se è fattibile con una sola passata if EgtCurveIsClosed( nCrv) then local nGrpTmp = EgtGroup( nGrpId, Frame3d( ORIG(), vtSlicing)) EgtRelocateGlob( nCrv, nGrpTmp) local dArea = EgtCurveAreaXY( nCrv) if dArea < 10 * GEO.EPS_SMALL then -- TODO curva generica local frLoc, dDimX, dDimY = EgtCurveMinAreaRectangleXY( nCrv) if dDimY < 10 * GEO.EPS_SMALL then local dZ = EgtSP( nCrv):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}) EgtErase( nCrv) EgtChangeId( nId, nCrv) end end end EgtRelocateGlob( nCrv, nGrpId, GDB_IN.LAST_SON) EgtErase( nGrpTmp) end return true 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 local nSrfDiff = EgtGetFirstNameInGroup( nShellNbrGrp, SHELL_NBR_SURF .. tostring( nInd)) local nOuterCrv = EgtGetFirstNameInGroup( nCrvGrpId, OUTER_CRV) while nOuterCrv do local nCopy = EgtCopyGlob( nOuterCrv, nGrpId) -- trim della curva con la regione con diverso numero di passate local nTrimCrv, nTrimCnt = EgtTrimCurveWithRegion( nCopy, nSrfDiff, false, false) if nTrimCnt ~= 0 then -- verifico se prima e ultima curva possono essere unite if nTrimCnt > 1 and AreSamePointApprox( EgtEP( nTrimCrv + nTrimCnt - 1), EgtSP( nTrimCrv)) then local nNewId = EgtCurveCompo( nGrpId, { nTrimCrv + nTrimCnt - 1, nTrimCrv}) EgtChangeId( nNewId, nTrimCrv) nTrimCnt = nTrimCnt - 1 end for nCrvT = nTrimCrv, nTrimCrv + nTrimCnt - 1 do -- calcolo offset della curva ( è il percorso della shell) EgtModifyCurveExtrusion( nCrvT, LayerParams.vtSlicing) 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 = VerifyExtraShellPath( nId, nGrpId, LayerParams.vtSlicing, LayerParams.dStrand) -- verifico se soddisfa vincolo sulla lunghezza if dLen > MIN_LEN and bValid then EgtModifyCurveExtrusion( nId, LayerParams.vtSlicing) EgtSetName( nId, EXTRA_SHELL_CRV .. tostring( nMaxShellNbrDiff - nInd + 1)) EgtSetInfo( nId, KEY_TYPE, TYPE.EXTRA_SHELL) -- aggiorno la superficie occupata dalle shell con quella appena calcolata UpdateTotalShellSurf( nSrfTrim, nId, 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 ReorderExtraShells( nGrpId, LayerParams.dStrand, vPtStart, LayerParams.bPrintInvert) return end else EgtErase( nId) end end end end end end nOuterCrv = EgtGetNextName( nOuterCrv, OUTER_CRV) end end -- riordino le curve appena create e se possibile creo percorsi chiusi ReorderExtraShells( nGrpId, LayerParams.dStrand, vPtStart, LayerParams.bPrintInvert) 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 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) -- regioni con diverso numero di passate local nShellNbrGrp = EgtGetFirstNameInGroup( vLayIds[nIdx], SHELL_NBR_GRP) CreateShellNbrSurfaces( nShellNbrGrp, LayerParams.nShellsNbr) 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 e il solido sono già stati calcolati 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 local nSolidGrpId = EgtGetFirstNameInGroup( nCrvGrpId, SOLID_GRP) or GDB_ID.NULL if nSolidGrpId ~= GDB_ID.NULL then EgtErase( nSolidGrpId) end -- recupero la superficie ottenuta dallo slicing local nSrf = EgtGetFirstNameInGroup( nCrvGrpId, LAYER_SRF) if nSrf then -- parete esterna local dOffs = 0.5 * LayerParams.dStrand - LayerParams.dOffs local bOk, bExists, nSrfId = ComputeSurfOffset( nSrf, nCrvGrpId, - dOffs) 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) -- pareti interne complete local nMaxShellNbrDiff = ComputeMaxShellNbrDiff( nSrf, nShellNbrSurfGrp) for nInd = 1, LayerParams.nShellsNbr - 1 - nMaxShellNbrDiff do -- offset della superficie originale dOffs = dOffs + LayerParams.dStrand local bOk, bExists, nSrfId = ComputeSurfOffset( nSrf, nCrvGrpId, - dOffs) 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, vPtStart) end EgtErase( nSrfId) end -- preparo superficie occupata dalle shell da usare per trim local bOkTrim, bExistsTrim, nSrfTrim = ComputeSurfOffset( nSrf, nCrvGrpId, - dOffs - LayerParams.dStrand + s_dOffsCorr) 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, vPtStart) end -- gestione eventuale floor if nIdx <= LayerParams.nFloorNbr then AddFloor( nSrf, nGrpId, LayerParams, nIdx) end end -- passo al gruppo di contorni successivo nCrvGrpId = EgtGetNextName( nCrvGrpId, CONTOUR_GRP.."*") or GDB_ID.NULL end -- sistemo eventuali costolature if nRibsGrp then CalcRibsPaths( vLayIds[nIdx], nRibsGrp, LayerParams, nIdx, nMaxStrandDiff) end if EgtProcessEvents( nIdx / #vLayIds * 100, 0) == 1 then EgtDraw() return end end end --------------------------------------------------------------------- return CalcPaths