Files
3dprinting/LuaLibs/CalcPaths.lua
T
SaraP 4a211ef9c3 3dPrinting :
- aggiunti parametri coasting e wipe nelle regioni con diverso numero di passate.
2022-08-26 10:38:51 +02:00

1106 lines
43 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 = 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