Files
3dprinting/LuaLibs/CalcPaths.lua
T
SaraP d775e0fe49 3dPrinting :
- aggiunto overlap tra passate.
2022-09-16 11:55:15 +02:00

1524 lines
61 KiB
Lua

-- 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.nShellsNbr = EgtGetInfo( s_nPartId, KEY_SHELLS_NBR, 'i')
LayerParams.dStrand = EgtGetInfo( s_nPartId, KEY_STRAND, '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)
-- 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])
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))
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)
-- 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)
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)
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)
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)
-- 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)
table.insert( vIds, j)
end
local vtS = EgtSV( nInd)
EgtErase( nId)
end
end
-------------------------------------------------------------------
--------------------------- RIBS -----------------------------------
--------------------------------------------------------------------
-- Funzione che sistema le intersezioni fra costolature nel caso generico
local function AdjustRibsOffsetForIntersection( nCrv1, nCrv2, LayerParams, nOffsGrp)
-- 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 nSrf = EgtSurfFrFatCurve( nOffsGrp, nCrv1, dOffs + ( 1 - nOverlap / 100) * LayerParams.dStrand, false)
-- recupero gli offset della curva secondaria ( nCrv2)
local vOffs2 = EgtGetNameInGroup( nOffsGrp, EgtGetName( nCrv2))
-- trim degli offset della curva secondaria
for i = 1, #vOffs2 do
local nId, nCnt = EgtTrimCurveWithRegion( vOffs2[i], nSrf, false, true)
EgtChangeId( nId, vOffs2[i])
if nCnt > 1 then
EgtSetInfo( nId + 1, KEY_SPLIT_RIB, vOffs2[i])
EgtRelocateGlob( nId + 1, nOffsGrp, GDB_IN.LAST_SON)
end
end
EgtErase( nSrf)
end
--------------------------------------------------------------------
-- Funzione che sistema le intersezioni fra costolature nel caso di 2 passate
local function AdjustRibsOffsetForIntersection2Shells( nCrv1, nCrv2, LayerParams, nOffsGrp, nOrigGrp)
-- recupero gli offset originali delle due curve
local vOffsOrig1 = EgtGetNameInGroup( nOrigGrp, EgtGetName( nCrv1))
local vOffsOrig2 = EgtGetNameInGroup( nOrigGrp, EgtGetName( nCrv2))
-- costruisco le superfici da usare per trim
local nOverlap = EgtGetInfo( nCrv1, KEY_RIBS_OVERLAP, 'i')
local dOffs = LayerParams.dStrand / 2 + ( 1 - nOverlap / 100) * LayerParams.dStrand
local nRect1 = EgtRectangle3P( nOffsGrp, EgtSP( vOffsOrig1[1]), EgtEP( vOffsOrig1[2]), EgtEP( vOffsOrig1[1]))
local nSrf1 = EgtSurfFlatRegion( nOffsGrp, {nRect1})
local vtN1 = EgtSurfFrNormVersor( nSrf1, GDB_ID.ROOT)
if LayerParams.vtSlicing * vtN1 < 0 then
EgtInvertSurf( nSrf1)
end
local nRect2 = EgtRectangle3P( nOffsGrp, EgtSP( vOffsOrig2[1]), EgtEP( vOffsOrig2[2]), EgtEP( vOffsOrig2[1]))
local nSrf2 = EgtSurfFlatRegion( nOffsGrp, {nRect2})
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( nRect1)
EgtErase( nSrf2)
EgtErase( nRect2)
end
--------------------------------------------------------------------
local function HandleRibsIntersections( nRibsGrp, LayerParams, nOffsGrp, nRibsPathGrp, bAllTwoStrands)
local nCrvGrp = EgtGetParent( nRibsPathGrp)
-- copio gli offset delle costolature nel RibsPathGrp
local vOffsRib = EgtGetAllInGroup( nOffsGrp)
for i = 1, #vOffsRib do
EgtCopyGlob( vOffsRib[i], nRibsPathGrp)
end
-- calcolo la regione nella quale ha senso considerare l'intersezione
local nSrf = EgtGetFirstNameInGroup( nCrvGrp, TOT_SHELL_TRIM_SURF)
local bOk, bExists, nSrfOffs = ComputeSurfOffset( nSrf, nCrvGrp, 2 * LayerParams.dStrand)
if not bOk or not bExists then
nSrfOffs = EgtCopyGlob( nSrf, nCrvGrp)
end
local vRibsIds = EgtGetNameInGroup( nRibsGrp, RIBS_CRV .. '*')
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
-- verifico se l'interserzione si trova nella regione dello slice
local nPtId = EgtPoint( nRibsPathGrp, ptInt)
if not EgtSurfFrTestExternal( nSrfOffs, nPtId) 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 nCrv1 = vRibsIds[i] -- curva principale che non viene tagliata
local nCrv2 = vRibsIds[j] -- curve secondaria da modificare
if dPar1 < 10 * GEO.EPS_SMALL or abs( dPar1 - dParE1) < 10 * GEO.EPS_SMALL then
nCrv1, nCrv2 = nCrv2, nCrv1
end
if bAllTwoStrands then
-- nel caso di 2 passate gestione speciale
AdjustRibsOffsetForIntersection2Shells( nCrv1, nCrv2, LayerParams, nRibsPathGrp, nOffsGrp)
else
AdjustRibsOffsetForIntersection( nCrv1, nCrv2, LayerParams, nRibsPathGrp)
end
end
EgtErase( nPtId)
end
end
end
EgtErase( nSrfOffs)
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
-- sistemo nomi
local kMax = nMaxNbr + 1
local dTol = 500 * GEO.EPS_SMALL
for i = 1, nMaxNbr do
local vIds = EgtGetNameInGroup( nGrp, RIBS_CRV .. tostring(i)) or {}
for j = 2, #vIds do
local dDistS = EgtPointCurveDist( EgtSP( vIds[j]), vIds[j-1])
local dDistM = EgtPointCurveDist( EgtMP( vIds[j]), vIds[j-1])
local dDistE = EgtPointCurveDist( EgtEP( vIds[j]), vIds[j-1])
if abs( dDistS - dStrand) < dTol or abs( dDistM - dStrand) < dTol or abs( dDistE - dStrand) < dTol 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
-- aggiusto tutte le costolature divise
for i = 1, #vSplitRibs do
local nPrevId = EgtGetInfo( vSplitRibs[i], KEY_SPLIT_RIB, 'i')
local bInverted = EgtGetInfo( vSplitRibs[i], KEY_INVERTED_CRV, 'b') or false
-- aggiungo come successiva alla costolatura da cui si è generata
EgtRelocateGlob( vSplitRibs[i], nPrevId, EgtIf( bInverted, GDB_IN.BEFORE, GDB_IN.AFTER))
-- correggo le info per gestire correttamente nel calcolo toolpath
if bInverted then
EgtRemoveInfo( vSplitRibs[i], KEY_SPLIT_RIB)
EgtSetInfo( nPrevId, KEY_SPLIT_RIB, vSplitRibs[i])
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')
CopyInfo( vOrig[i], nId, KEY_ASSOCIATED_SURF, '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)
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 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
-- 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 = ComputeTrimSurfWithOverlaps( vRibs, nSrfBase, KEY_RIBS_OVERLAP, LayerParams.dStrand, nRibsPathGrp)
-- 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 < MIN_RIBS_LEN then
EgtErase( nCrv + nInd)
else
table.insert( tOldNewIds[ vOrderedRibs[i]], nCrv + nInd)
-- controllo la direzione (consideriamo inclinazione solo lungo X)
local vtDir = EgtMV( nCrv + nInd)
local dXl = sqrt( sqr( vtDir:getX()) + sqr( vtDir:getZ()))
local dYl = abs( vtDir:getY())
local dVal = EgtIf( dXl > dYl - GEO.EPS_SMALL, vtDir:getX(), vtDir:getY())
if dVal < - GEO.EPS_SMALL then
EgtInvertCurve( nCrv + nInd)
EgtSetInfo( nCrv + nInd, KEY_INVERTED_CRV, 1)
end
-- salvo info della superficie di trim associata
EgtSetInfo( nCrv + nInd, KEY_ASSOCIATED_SURF, vSurfOffs[nOverlap])
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
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, nCnt = EgtSurfFlatRegion( nSrfGrp, vCrvIds)
for nIdSrf = nSrfId + 1, nSrfId + nCnt - 1 do
EgtSurfFrAdd( nSrfId, nIdSrf)
EgtErase( 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 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])
EgtSetInfo( vIds[i], KEY_INVERTED_CRV, 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)
-- 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 - LayerParams.nStrandOverlap / 100)
local nSrfDiff = EgtGetFirstNameInGroup( nShellNbrGrp, SHELL_NBR_SURF .. tostring( nInd))
local nOuterCrv = EgtGetFirstNameInGroup( nCrvGrpId, OUTER_CRV)
while nOuterCrv do
local nCopy = EgtCopyGlob( nOuterCrv, nGrpId)
ModifyStartPoint( nCopy, vPtStart)
-- 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 = 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
EgtModifyCurveExtrusion( nId, LayerParams.vtSlicing)
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
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)
-- offset della superifice del solido
local bOk, bExists, nSrfOffs = ComputeSurfOffset( nSrfSolid, nCrvGrp, dStrand)
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])
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) + dStrand * vtYLoc
local ptE = EgtEP( vIds[i]) + dStrand * vtYLoc
local nExtraCrv = EgtLine( nGrp, ptS, ptE)
-- 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)
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)
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)
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
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 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
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 * ( 1 - LayerParams.nStrandOverlap / 100)
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)
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
-- 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)
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)
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, nMaxStrandDiff)
end
end
if EgtProcessEvents( EgtIf( PRINT, 100, 0) + nIdx / #vLayIds * 100, 0) == 1 then
EgtDraw()
return
end
end
end
---------------------------------------------------------------------
return CalcPaths