Files
3dprinting/LuaLibs/CalcPaths.lua
T
SaraP bc3cf3b3a9 3dPrinting :
- corretto errore reduced shell number di area nulla.
2023-06-08 10:34:42 +02:00

3068 lines
124 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 s_vErr = {}
local s_nCurrIdx
---------------------------------------------------------------------
local function GetLayerParamsForPathCalc()
local LayerParams = {}
LayerParams.bSpiralVase = EgtGetInfo( s_nPartId, KEY_SPIRAL_VASE, 'b') or false
LayerParams.nShellsNbr = EgtGetInfo( s_nPartId, KEY_SHELLS_NBR, 'i')
LayerParams.dStrand = EgtGetInfo( s_nPartId, KEY_STRAND, 'd')
LayerParams.dLayHeight = EgtGetInfo( s_nPartId, KEY_SLICE_STEP, 'd')
LayerParams.nStrandOverlap = EgtGetInfo( s_nPartId, KEY_STRAND_OVERLAP, 'i') or 0
LayerParams.dOffs = EgtGetInfo( s_nPartId, KEY_OFFSET_SLICE, 'd')
LayerParams.vtSlicing = EgtGetInfo( s_nPartId, KEY_SLICING_DIR, 'v')
LayerParams.bPrintInvert = ( EgtGetInfo( s_nPartId, KEY_PRINT_DIRECTION, 'i') == PRINT_DIRECTION.CW)
LayerParams.vPrintOrder = EgtGetInfo( s_nPartId, KEY_PRINT_ORDER, 'vi') or { 1, 2, 3, 4, 5, 6, 7, 8}
-- parametri costolature
LayerParams.bRibsInvertOrder = EgtGetInfo( s_nPartId, KEY_RIBS_INVERT_ORDER, 'b')
-- parametri regioni con diverse passate
LayerParams.dShellNbrCoasting = EgtGetInfo( s_nPartId, KEY_SHELL_NBR_COASTING, 'd')
LayerParams.dShellNbrWipe = EgtGetInfo( s_nPartId, KEY_SHELL_NBR_WIPE, 'd')
LayerParams.dShellNbrWipeDir = EgtGetInfo( s_nPartId, KEY_SHELL_NBR_WIPE_DIR, 'd')
-- parametri solid fill
LayerParams.nFloorNbr = EgtGetInfo( s_nPartId, KEY_FLOOR_NBR, 'i') or 0
LayerParams.nFloorType = EgtGetInfo( s_nPartId, KEY_FLOOR_TYPE, 'i') or FILL_TYPE.OFFSET
LayerParams.nCeilNbr = EgtGetInfo( s_nPartId, KEY_CEIL_NBR, 'i') or 0
LayerParams.nCeilType = EgtGetInfo( s_nPartId, KEY_CEIL_TYPE, 'i') or FILL_TYPE.OFFSET
-- parametri infill
LayerParams.nInfillOverlap = EgtGetInfo( s_nPartId, KEY_INFILL_OVERLAP, 'i') or 0
LayerParams.nInfillType = EgtGetInfo( s_nPartId, KEY_INFILL_TYPE, 'i') or FILL_TYPE.NONE
-- eventuale modifica dei parametri per gestire correttamente il caso spiral vase
if LayerParams.bSpiralVase then
LayerParams.nShellsNbr = 1
LayerParams.nFloorNbr = 0
LayerParams.nCeilNbr = 0
end
return LayerParams
end
--------------------------------------------------------------------------------------------
local function CopyInfo( nSouId, nDestId, sInfo, sType)
local info = EgtGetInfo( nSouId, sInfo, sType)
EgtSetInfo( nDestId, sInfo, info)
end
-------------------------------------------------------------------
local function SwapInfo( nId1, nId2, sInfo, sType, sDefVal)
local info1 = EgtGetInfo( nId1, sInfo, sType) or sDefVal
local info2 = EgtGetInfo( nId2, sInfo, sType) or sDefVal
EgtSetInfo( nId1, sInfo, info2)
EgtSetInfo( nId2, sInfo, info1)
end
--------------------------------------------------------------------------------------------
local function UpdateInvertInfo( nId)
local bInvert = EgtGetInfo( nId, KEY_INVERTED_CRV, 'b') or false
EgtSetInfo( nId, KEY_INVERTED_CRV, not bInvert)
end
----------------------------------------------------------------------
local function ComputeSurfOffset( nSrf, nGrpId, dOffs, vtSlicing, nOffsType)
-- tipologia di offset
if not nOffsType then nOffsType = GDB_OT.FILLET end
-- gruppo temporaneo locale
local nGrpTmp = EgtGroup( nGrpId, Frame3d( ORIG(), vtSlicing), GDB_RT.GLOB)
local nCopySrf = EgtCopyGlob( nSrf, nGrpTmp) or GDB_ID.NULL
local bOk = EgtSurfFrOffset( nCopySrf, dOffs, nOffsType)
local bExists = EgtSurfFrChunkCount( nCopySrf) > 0
if not bOk or not bExists then
EgtErase( nCopySrf)
nCopySrf = EgtCopyGlob( nSrf, nGrpTmp) or GDB_ID.NULL
bOk = EgtSurfFrOffset( nCopySrf, dOffs + 0.05)
bExists = EgtSurfFrChunkCount( nCopySrf) > 0
end
EgtRelocateGlob( nCopySrf, nGrpId)
EgtErase( nGrpTmp)
if not bExists then
nCopySrf = GDB_ID.NULL
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
if #vPtStart == 1 then
nMinIdx = 1
else
local dMinDist = GEO.INFINITO
for i = 1, #vPtStart do
local dDist = EgtPointCurveDist( vPtStart[i], nCrvId)
if dDist < dMinDist - 10 * GEO.EPS_SMALL then
dMinDist = dDist
nMinIdx = i
end
end
end
EgtChangeClosedCurveStartPoint( nCrvId, vPtStart[nMinIdx])
end
end
---------------------------------------------------------------------
local function GetPathsFromSurf( nSrfId, sName, nType, nGrpId, vPtStart)
local vIds = {}
local nChunks = EgtSurfFrChunkCount( nSrfId)
for nC = 0, nChunks - 1 do
-- estraggo i contorni
local nCrvId, nCrvCnt = EgtExtractSurfFrChunkLoops( nSrfId, nC, nGrpId)
for nInd = 0, nCrvCnt - 1 do
EgtSetName( nCrvId + nInd, sName)
EgtSetInfo( nCrvId + nInd, KEY_TYPE, nType)
-- se è loop interno lo inverto per averlo orientato in senso antiorario
if nInd > 0 then
EgtInvertCurve( nCrvId + nInd)
EgtSetInfo( nCrvId + nInd, KEY_INTERNAL_SRF_LOOP, true)
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)
-- TODO migliorare il controllo per verificare se sovrapposizione
local dAllowedOverlap = 1
local nRes, nCnt = EgtOffsetCurveAdv( nCrvId, - dStrand / 2 + dAllowedOverlap)
-- se errore ritento con valore leggermente modificato
if not nRes then
nRes, nCnt = EgtOffsetCurveAdv( nCrvId, - dStrand / 2 + 0.05)
if not nRes then return false end
end
for j = nRes, nRes + nCnt - 1 do
EgtErase( j)
end
if nRes == GDB_ID.NULL or not dArea or dArea < GEO.EPS_SMALL then
-- verifico se fattibile con una sola passata
-- TODO da sistemare con medial axis per curva generica
local bSingleStrand = false
if EgtCurveIsClosed( nCrvId) then
local nGrpTmp = EgtGroup( nGrp, Frame3d( ORIG(), vtSlicing), GDB_RT.GLOB)
EgtRelocateGlob( nCrvId, nGrpTmp)
local frLoc, dDimX, dDimY = EgtCurveMinAreaRectangleXY( nCrvId)
if dDimY < 0.5 then
-- TODO curva generica
local dZ = EgtSP( nCrvId):getZ()
-- creo la curva che corrisponde alla sigola passata
local ptS = frLoc:getOrigin() - dDimX / 2 * frLoc:getVersX() + dZ * Z_AX()
local ptE = frLoc:getOrigin() + dDimX / 2 * frLoc:getVersX() + dZ * Z_AX()
if dist( ptS, ptE) > 5 then
local nId = EgtCurveCompoFromPoints( nGrpTmp, { ptS, ptE})
local sName = EgtGetName( nCrvId)
if sName then EgtSetName( nId, sName) end
local nType = EgtGetInfo( nCrvId, KEY_TYPE, 'i')
if nType then EgtSetInfo( nId, KEY_TYPE, nType) end
EgtErase( nCrvId)
EgtChangeId( nId, nCrvId)
bSingleStrand = true
end
end
EgtRelocateGlob( nCrvId, nGrp, GDB_IN.LAST_SON)
EgtErase( nGrpTmp)
end
-- se non è fattibile con unica passata lo cancello
if not bSingleStrand then
-- verifico se devo eliminarlo dalle info della curva precedente
local nPrev = EgtGetInfo( nCrvId, KEY_PREV_CRV, 'i')
if nPrev then
local vNext = EgtGetInfo( nPrev, KEY_NEXT_CRVS, 'vi')
if vNext then
for k = 1, #vNext do
if vNext[k] == nCrvId then
table.remove( vNext, k)
break
end
end
EgtSetInfo( nPrev, KEY_NEXT_CRVS, vNext)
end
end
-- cancello
EgtErase( nCrvId)
return false
end
end
return true
end
--------------------------------------------------------------------
------------------------- INFILL -----------------------------------
--------------------------------------------------------------------
local function CalcInfillPaths( nLayId, nInfillGrp, LayerParams)
if not nInfillGrp then return end
-- recupero le curve di infill
local vIds = EgtGetAllInGroup( nInfillGrp)
if not vIds or #vIds == 0 then return end
-- scorro i gruppi di curve
local vCrvGrps = EgtGetNameInGroup( nLayId, CONTOUR_GRP .. '*')
for i = 1, #vCrvGrps do
-- creo il gruppo per infill
local nInfillPathGrp = EgtGroup( vCrvGrps[i])
EgtSetName( nInfillPathGrp, INFILL_GRP)
EgtSetStatus( nInfillPathGrp, GDB_ST.OFF)
EgtSetInfo( nInfillPathGrp, KEY_FILL_TYPE, LayerParams.nInfillType)
-- recupero la superficie con cui fare trim
local nSrf = EgtGetFirstNameInGroup( vCrvGrps[i], TOT_SHELL_TRIM_SURF)
if not nSrf then
-- se non esiste non c'è spazio per infill
EgtOutLog( 'Warning: Infill not possibile (layer '.. EgtNumToString( s_nCurrIdx) ..') - CalcPaths')
else
local bOk, bExists, nTrimSrf = ComputeSurfOffset( nSrf, nInfillPathGrp, LayerParams.nInfillOverlap / 100 * LayerParams.dStrand, LayerParams.vtSlicing, GDB_OT.EXTEND)
if not bOk then
-- eseguo trim senza overlap
EgtOutLog( 'Warning: Infill without correct overlap (layer '.. EgtNumToString( s_nCurrIdx) ..') - CalcPaths')
nTrimSrf = EgtCopyGlob( nSrf, nInfillPathGrp)
end
for i = 1, #vIds do
local nNewId = EgtCopyGlob( vIds[i], nInfillPathGrp)
-- faccio trim con la superficie
local nRes, nCnt = EgtTrimCurveWithRegion( nNewId, nTrimSrf, true, true)
for nId = nRes, nRes + nCnt - 1 do
-- verifico se lunghezza minima
local dLen = EgtCurveLength( nId)
if dLen < MIN_INFILL_LEN then
EgtErase( nId)
else
EgtSetName( nId, INFILL_CRV)
EgtSetInfo( nId, KEY_TYPE, TYPE.INFILL)
EgtSetInfo( nId, KEY_ASSOCIATED_SURF, nTrimSrf)
EgtModifyCurveExtrusion( nId, LayerParams.vtSlicing)
end
end
end
-- avendo riempito la regione con gli infill, la TotShellTrimSurf non deve esistere
EgtErase( nSrf)
end
-- se gruppo vuoto lo cancello
if not EgtGetFirstNameInGroup( nInfillPathGrp, INFILL_CRV .. '*') then
EgtErase( nInfillPathGrp)
end
end
return true
end
--------------------------------------------------------------------
------------------------ SOLID FILL --------------------------------
--------------------------------------------------------------------
local function AssignChildrenCurves( vParentIds, vChildrenIds, vOrdered)
if not vParentIds or not vChildrenIds then return end
if #vParentIds == 1 then
vOrdered[vParentIds[1]] = vChildrenIds
else
-- recupero i centroidi di tutte le curve padre
local vPtCParent = {}
for i = 1, #vParentIds do
table.insert( vPtCParent, EgtGP( vParentIds[i]))
end
-- associo ad ogni elemento di vParentIds gli elementi di vChildrenIds che ha generato
for i = 1, #vChildrenIds do
-- individuo la curva di vParentIds con il centroiode più vicino
local ptC = EgtGP( vChildrenIds[i])
local dDistMin = GEO.INFINITO
local nParentId = -1
for j = 1, #vPtCParent do
local dCurrDist = dist( ptC, vPtCParent[j])
if dCurrDist < dDistMin - GEO.EPS_SMALL then
dDistMin = dCurrDist
nParentId = vParentIds[j]
end
end
-- la aggiungo tra i figli della curva di vParentIds trovata
if not vOrdered[nParentId] then
vOrdered[nParentId] = {vChildrenIds[i]}
else
table.insert( vOrdered[nParentId], vChildrenIds[i])
end
end
end
end
---------------------------------------------------------------------------
local function ReorderPath( vOldIds, vNewIds)
if not vNewIds or not vOldIds then return end
-- suddivido in base alla tipologia di loop ( esterno o interno)
local tOldIds = {{}, {}}
for i = 1, #vOldIds do
local bIntLoop = EgtGetInfo( vOldIds[i], KEY_INTERNAL_SRF_LOOP, 'b') or false
local nTabInd = EgtIf( bIntLoop, 2, 1)
table.insert( tOldIds[nTabInd], vOldIds[i])
end
local tNewIds = {{}, {}}
for i = 1, #vNewIds do
local bIntLoop = EgtGetInfo( vNewIds[i], KEY_INTERNAL_SRF_LOOP, 'b') or false
local nTabInd = EgtIf( bIntLoop, 2, 1)
table.insert( tNewIds[nTabInd], vNewIds[i])
end
-- assegno ad ogni curva di vOldIds le curve di vNewIds che ha generato
local vOrdered = {}
AssignChildrenCurves( tOldIds[1], tNewIds[1], vOrdered) -- loop esterni
AssignChildrenCurves( tOldIds[2], tNewIds[2], vOrdered) -- loop interni
-- assegno le info e riordino
local vNewOrder = {}
local nGrp = EgtGetParent( vNewIds[1])
for i = 1, #vOldIds do
local vChildrenIds = vOrdered[vOldIds[i]] or {}
EgtSetInfo( vOldIds[i], KEY_NEXT_CRVS, vChildrenIds)
for j = 1, #vChildrenIds do
EgtRelocateGlob( vChildrenIds[j], nGrp, GDB_IN.LAST_SON)
table.insert( vNewOrder, vChildrenIds[j])
EgtSetInfo( vChildrenIds[j], KEY_PREV_CRV, vOldIds[i])
end
end
return vNewOrder
end
---------------------------------------------------------------------------
local function ComputeOffsetSolidFill( nSrf, dStrand, vtSlicing, sName, nType, nGrp, vPtStart, vOldIds)
-- nSrf è già la prima superficie da cui estrarre i bordi, quindi il primo offset non va fatto
local dOffs = 0
local nSrfOffs = EgtCopyGlob( nSrf, nGrp)
local bOk = true
local bExists = ( EgtSurfFrChunkCount( nSrf) > 0)
while bOk and bExists do
-- estraggo i contorni
local vNewIds = GetPathsFromSurf( nSrfOffs, sName, nType, nGrp, vPtStart)
if vNewIds then
-- riordino
local vNewOrder = ReorderPath( vOldIds, vNewIds) or vNewIds
-- verifico fattibilità
local k = 1
while k <= #vNewOrder do
if VerifyPath( vNewOrder[k], dStrand, vtSlicing, nGrp) then
k = k + 1
else
-- se non è fattibile lo rimuovo dalla table per non ritrovarlo nello step successivo
table.remove( vNewOrder, k)
end
end
vOldIds = vNewOrder
end
-- offset successivo
EgtErase( nSrfOffs)
dOffs = dOffs - dStrand
bOk, bExists, nSrfOffs = ComputeSurfOffset( nSrf, nGrp, dOffs, vtSlicing)
end
end
------------------------------------------------------------------
local function FindOptimalZigZagDirection( nSrfId, nBorderSurf, dStrand, nGrp, frLoc)
-- come direzione ottimale scelgo quella del lato più vicino al bordo oppure quella del
-- lato più lungo nel caso in cui i lati fossero tutti sufficientemente lontani ( distanza > dStrand) dal bordo
local nGrpTmp = EgtGroup( nGrp, frLoc, GDB_RT.GLOB) -- gruppo temporaneo per i conti
local dTol = 1 + GEO.EPS_SMALL
-- recupero tutti i lati della superficie da riempire
local vCrvIds = GetPathsFromSurf( nSrfId, 'Tmp', 0, nGrpTmp)
local nId, nCnt = EgtExplodeCurveCompo( vCrvIds[1])
local vAllIds = {}
for i = nId, nId + nCnt - 1 do
table.insert( vAllIds, i)
end
local vCheckIds = {}
-- se ho superficie che contiene nSrfId ( caso AuxSolid) cerco il lato di lunghezza massima tra quelli a distanza minima dal bordo
if nBorderSurf then
-- recupero i contorni della curva di bordo
local vBorderIds = GetPathsFromSurf( nBorderSurf, 'TmpBorder', 0, nGrpTmp)
local dMinDist = GEO.INFINITO
for i = nId, nId + nCnt - 1 do
-- trovo la distanza minima dalle curve di bordo
local dDist
if #vBorderIds == 1 then
dDist = EgtPointCurveDist( EgtMP( i), vBorderIds[1])
else
dDist = GEO.INFINITO
for j = 1, #vBorderIds do
local dCurrDist = EgtPointCurveDist( EgtMP( i), vBorderIds[j])
if dCurrDist < dDist then
dDist = dCurrDist
end
end
end
-- se tratto sufficientemente vicino al bordo verifico se a distanza minima ( entro tolleranza dTol)
if dDist < dStrand + GEO.EPS_SMALL then
if abs( dDist - dMinDist) < dTol then
table.insert( vCheckIds, i)
elseif dDist < dMinDist - dTol then
dMinDist = dDist
vCheckIds = {i}
end
end
end
end
-- se non ho id specifici da controllare considero tutti i lati
if #vCheckIds == 0 then
vCheckIds = vAllIds
end
-- cerco il lato più lungo tra quelli selezionati
local vtDir
if #vCheckIds == 1 then
vtDir = EgtSV( vCheckIds[1])
else
local dLen = - GEO.INFINITO
for k = 1, #vCheckIds do
local dCurrLen = EgtCurveLength( vCheckIds[k])
if dCurrLen > dLen + GEO.EPS_SMALL then
dLen = dCurrLen
vtDir = EgtSV( vCheckIds[k])
end
end
end
EgtErase( nGrpTmp)
return vtDir
end
--------------------------------------------------------------------
local function ComputeZigZagSolidFill( nSrf, dStrand, vtSlicing, sName, nType, nGrp, nBorderSurf)
if EgtSurfFrChunkCount( nSrf) == 0 then return end
local nCopySrf = EgtCopyGlob( nSrf, nGrp)
local frLoc = Frame3d( ORIG(), vtSlicing)
-- analizzo tutti i chunk della superifice da riempire
local nFirst, nSrfCnt = EgtExplodeSurf( nCopySrf)
local vIds = {}
for nSrfId = nFirst, nFirst + nSrfCnt - 1 do
-- trovo la direzione ottimale per la svuotatura in frLoc
local vtDir = FindOptimalZigZagDirection( nSrfId, nBorderSurf, dStrand, nGrp, frLoc)
local _, _, dAng = SphericalFromVector( vtDir)
vtDir:toGlob( frLoc)
local nInd, nCnt = EgtGetSurfFrZigZagInfill( nSrfId, nGrp, dStrand, dAng, false, false)
if nInd then
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, true)
EgtModifyCurveExtrusion( j, vtSlicing, GDB_RT.GLOB)
table.insert( vIds, j)
end
end
EgtErase( nSrfId)
end
end
------------------------------------------------------------------
local function CalcSolidFillPath( nLayId, LayerParams, vPtStart, nFillType)
-- scorro i gruppi di curve
local vCrvGrps = EgtGetNameInGroup( nLayId, CONTOUR_GRP .. '*')
for i = 1, #vCrvGrps do
-- creo il gruppo per infill
local nInfillPathGrp = EgtGroup( vCrvGrps[i])
EgtSetName( nInfillPathGrp, INFILL_GRP)
EgtSetStatus( nInfillPathGrp, GDB_ST.OFF)
EgtSetInfo( nInfillPathGrp, KEY_FILL_TYPE, nFillType)
-- recupero la superficie da riempire
local nSrf = EgtGetFirstNameInGroup( vCrvGrps[i], TOT_SHELL_TRIM_SURF)
if not nSrf then
-- se non esiste non c'è spazio per solid fill
EgtOutLog( 'Warning: SolidFill not possibile (layer '.. EgtNumToString( s_nCurrIdx) ..') - CalcPaths')
else
local bOk, bExists, nSrfToFill = ComputeSurfOffset( nSrf, nInfillPathGrp, LayerParams.nStrandOverlap / 100 * LayerParams.dStrand, LayerParams.vtSlicing)
if not bOk then
-- eseguo trim senza overlap
EgtOutLog( 'Warning: SolidFill without correct overlap (layer '.. EgtNumToString( s_nCurrIdx) ..') - CalcPaths')
nSrfToFill = EgtCopyGlob( nSrf, nInfillPathGrp)
end
-- distanza tra passate tenendo conto dell'overlap indicato
local dDist = ( 1 - LayerParams.nStrandOverlap / 100) * LayerParams.dStrand
-- inserisco il riempimento
if nFillType == FILL_TYPE.OFFSET then
-- recupero le shell precedenti dal PathGrp
local nPathGrp = EgtGetFirstNameInGroup( vCrvGrps[i], PATH_GRP)
local nLast = EgtGetLastNameInGroup( nPathGrp, SHELL_CRV .. '*') or EgtGetLastNameInGroup( nPathGrp, EXTRA_SHELL_CRV .. '*')
local vOldIds = EgtGetNameInGroup( nPathGrp, EgtGetName( nLast))
ComputeOffsetSolidFill( nSrfToFill, dDist, LayerParams.vtSlicing, INFILL_CRV, TYPE.INFILL, nInfillPathGrp, vPtStart, vOldIds)
elseif nFillType == FILL_TYPE.ZIGZAG then
ComputeZigZagSolidFill( nSrfToFill, dDist, LayerParams.vtSlicing, INFILL_CRV, TYPE.INFILL, nInfillPathGrp)
end
-- avendo riempito la regione, la TotShellTrimSurf non deve esistere
EgtErase( nSrf)
end
-- se gruppo vuoto lo cancello
if not EgtGetFirstInGroup( nInfillPathGrp) then
EgtErase( nInfillPathGrp)
end
end
end
--------------------------------------------------------------------
--------------------------- RIBS -----------------------------------
--------------------------------------------------------------------
local function VerifyRibsHoles( vIds, dStrand)
local sPrevName = EgtGetName( vIds[1])
local i = 2
while i <= #vIds do
local bAdd = false
local sCurrName = EgtGetName( vIds[i])
-- se derivano dallo stesso setto verifico se possono essere uniti
if sCurrName == sPrevName then
local ptS1 = EgtSP( vIds[i-1])
local ptE1 = EgtEP( vIds[i-1])
local ptS2 = EgtSP( vIds[i])
local ptE2 = EgtEP( vIds[i])
local bAdd1 = dist( ptS1, ptE2) < dStrand + 10 * GEO.EPS_SMALL or dist( ptS1, ptS2) < dStrand + 10 * GEO.EPS_SMALL
local bAdd2 = dist( ptE1, ptS2) < dStrand + 10 * GEO.EPS_SMALL or dist( ptE1, ptE2) < dStrand + 10 * GEO.EPS_SMALL
local bInvert = dist( ptE1, ptE2) < dStrand + 10 * GEO.EPS_SMALL or dist( ptS1, ptS2) < dStrand + 10 * GEO.EPS_SMALL
if bInvert then
EgtInvertCurve( vIds[i])
end
if bAdd1 and bAdd2 then
-- se da unire in setto chiuso
bAdd = true
EgtAddCurveCompoLine( vIds[i-1], EgtEP( vIds[i]), false)
EgtAddCurveCompoLine( vIds[i-1], EgtSP( vIds[i]))
EgtAddCurveCompoCurve( vIds[i-1], vIds[i])
table.remove( vIds, i) -- rimuovo il setto dalla tabella
elseif bAdd2 then
bAdd = true
-- unisco il secondo tratto al primo
EgtAddCurveCompoLine( vIds[i-1], EgtSP( vIds[i]))
EgtAddCurveCompoCurve( vIds[i-1], vIds[i])
table.remove( vIds, i) -- rimuovo il setto dalla tabella
elseif bAdd1 then
bAdd = true
-- unisco il primo tratto al secondo
EgtAddCurveCompoLine( vIds[i], EgtSP( vIds[i-1]))
EgtAddCurveCompoCurve( vIds[i], vIds[i-1])
table.remove( vIds, i-1) -- rimuovo il setto dalla tabella
end
end
-- aggiorno per iterazione successiva
sPrevName = sCurrName
if not bAdd then
i = i + 1
end
end
end
--------------------------------------------------------------------
local function FindRibsUserLinkDirection( nCrv1, nCrv2, vtSlicing)
-- stabilisco l'orientamento del link
local bCCW = false
-- costruisco la superficie "definita" dal setto di partenza con i primi due setti che lo definiscono
local nGrpTmp = EgtGroup( EgtGetParent( nCrv1))
local nSrfLoop = EgtCurveCompoFromPoints( nGrpTmp, {EgtEP( nCrv1), EgtSP( nCrv2)})
if not nSrfLoop then return false end
EgtAddCurveCompoLine( nSrfLoop, EgtSP( nCrv2) + 100 * EgtSV( nCrv2))
EgtAddCurveCompoLine( nSrfLoop, EgtEP( nCrv1) - 100 * EgtEV( nCrv1))
EgtCloseCurveCompo( nSrfLoop)
local nSurf = EgtSurfFlatRegion( nGrpTmp, {nSrfLoop})
if not nSurf then
EgtErase( nGrpTmp)
return
end
-- verifico direzione della normale
local vtN = EgtSurfFrNormVersor( nSurf, GDB_ID.ROOT)
if AreSameVectorApprox( vtN, vtSlicing) then
bCCW = true
end
EgtErase( nGrpTmp)
return bCCW
end
-----------------------------------------------------------------------
local function FindAssociatedUserLinkParts( nStartRib, vRibs, vUsed, nGrpTmp, nType, nSrfTest)
local tabUserLink = {}
for i = 1, #vRibs do
local nTypeCurr = EgtGetInfo( vRibs[i], KEY_RIBS_TYPE, 'i')
-- verifico che il setto non sia già stato utilizzato in un altro UserLink e sia di tipologia compatibile
if not vUsed[vRibs[i]] and nTypeCurr == nType then
-- recupero setto di partenza non trimmato
local nStartId = EgtGetInfo( vRibs[i], KEY_START_RIB, 'i')
-- verifico se interseca nStartRib con un estremo
local dParS = EgtCurveParamAtPoint( nStartRib, EgtSP( nStartId), 100 * GEO.EPS_SMALL)
local dParE = EgtCurveParamAtPoint( nStartRib, EgtEP( nStartId), 100 * GEO.EPS_SMALL)
if dParS and dParE then
-- se entrambi gli estremi non ha senso aggiungerlo a UserLink
elseif dParS or dParE then
-- se solo un estremo verifico se si unisce a UserLink in tratto sensato
local dPar = dParS or dParE
local ptTest = EgtPoint( nGrpTmp, EgtUP( nStartRib, dPar))
local bExtJoint = EgtSurfFrTestExternal( nSrfTest, ptTest)
if ( nType == RIB_TYPE.EXTERNAL and not bExtJoint) or ( nType ~= RIB_TYPE.EXTERNAL and bExtJoint) then
-- lo aggiungo alla tabella di UserLink
local tRib = { nId = vRibs[i], bStart = EgtIf( dParS, true, false), bOn = false, dPar = dPar}
table.insert( tabUserLink, tRib)
-- indico che il setto è stato utilizzato
vUsed[vRibs[i]] = 1
end
end
end
end
return tabUserLink
end
-----------------------------------------------------------------------
local function AssignUserLinkInfo( tabUserLink, bCCW, bLoopRib, bSameSide, sName)
-- ordino per paramentro crescente
table.sort( tabUserLink, function(a,b) return a.dPar < b.dPar end)
-- aggiorno le info dei tratti di UserLink per tenere conto delle aggiunte
local bUseOppositeCondition = EgtIf( bSameSide, false, true)
for i = 1, #tabUserLink do
local nId = tabUserLink[i].nId
EgtSetName( nId, sName)
EgtSetInfo( nId, KEY_RIBS_USER_LINK, 1)
EgtSetInfo( nId, KEY_RIBS_USER_LINK_CCW, bCCW)
EgtSetInfo( nId, KEY_LOOP_RIB, bLoopRib)
EgtSetInfo( nId, KEY_RIBS_USER_LINK_SAME_SIDE, bSameSide)
EgtSetInfo( nId, KEY_RIBS_USER_LINK_TOT, #tabUserLink)
-- riposiziono
if i > 1 then
EgtRelocateGlob( nId, tabUserLink[i-1].nId, GDB_IN.AFTER)
end
-- ordine
local nPrevOrd = EgtGetInfo( nId, KEY_RIBS_USER_LINK_ORDER, 'i')
local nCurrOrd = i - 1
EgtSetInfo( nId, KEY_RIBS_USER_LINK_ORDER, nCurrOrd)
-- orientamento
if tabUserLink[i].bOn then
-- se il tratto apparteneva già a UserLink va invertito se order passa da pari a dispari o viceversa
local bInvert = ( nPrevOrd and nPrevOrd % 2 ~= nCurrOrd % 2) or ( not nPrevOrd and i ~= 1 and i % 2 ~= 0)
if bInvert then
EgtInvertCurve( nId)
UpdateInvertInfo( nId)
end
if not bSameSide then bUseOppositeCondition = not bUseOppositeCondition end
else
-- se tratto aggiunto dipende con quale estremo interseca il setto
local bCondition = ( nCurrOrd % 2 == 0 and tabUserLink[i].bStart) or ( nCurrOrd % 2 ~= 0 and not tabUserLink[i].bStart)
if bUseOppositeCondition ~= bCondition then
EgtInvertCurve( nId)
UpdateInvertInfo( nId)
end
end
end
end
------------------------------------------------------------------------
local function AdjustUserLinkRibs( tUserLink, vRibs, vtSlicing, nSrfInt, nSrfExt, nGrp)
local nGrpTmp = EgtGroup( nGrp) -- gruppo temporaneo per conti
local vUsed = {} -- setti di vRibs utilizzati per UserLink
-- verifico se posso aggiungere tratti extra agli UserLink già individuati
for nStartRib, vAssociatedRibs in pairs( tUserLink) do
-- verifico se ho tratti singoli da aggiungere a UserLink definito da nStartRib
local nType = EgtGetInfo( nStartRib, KEY_RIBS_TYPE, 'i')
local nSrfTest = EgtIf( nType == RIB_TYPE.EXTERNAL, nSrfExt, nSrfInt)
local tabUserLink = FindAssociatedUserLinkParts( nStartRib, vRibs, vUsed, nGrpTmp, nType, nSrfTest)
-- se ho tratti da aggiungere
if #tabUserLink > 0 then
-- recupero i tratti già individuati su UserLink
for i = 1, #vAssociatedRibs do
local dPar = EgtCurveParamAtPoint( nStartRib, EgtSP( vAssociatedRibs[i]), 100 * GEO.EPS_SMALL)
local tRib = { nId = vAssociatedRibs[i], bStart = true, bOn = true, dPar = dPar}
table.insert( tabUserLink, tRib)
end
-- recupero alcune info utili relative a UserLink
local bCCW = EgtGetInfo( vAssociatedRibs[1], KEY_RIBS_USER_LINK_CCW, 'b') or false
local bLoopRib = EgtGetInfo( vAssociatedRibs[1], KEY_LOOP_RIB, 'b') or false
local bSameSide = EgtGetInfo( vAssociatedRibs[1], KEY_RIBS_USER_LINK_SAME_SIDE, 'b') or false
local sName = EgtGetName( vAssociatedRibs[1])
-- assegno le proprietà
AssignUserLinkInfo( tabUserLink, bCCW, bLoopRib, bSameSide, sName)
end
end
-- verifico se tra i setti singoli rimasti posso trovare nuovi UserLink
for i = 1, #vRibs do
if not vUsed[vRibs[i]] then
-- indico il corrente come utilizzato per non ricontrollarlo in FindAssociatedUserLinkParts
vUsed[vRibs[i]] = 1
-- verifico se trovo setti associati ( e quindi definisce UserLink)
local nStartRib = EgtGetInfo( vRibs[i], KEY_START_RIB, 'i')
local nType = EgtGetInfo( vRibs[i], KEY_RIBS_TYPE, 'i')
local nSrfTest = EgtIf( nType == RIB_TYPE.EXTERNAL, nSrfExt, nSrfInt)
local tabUserLink = FindAssociatedUserLinkParts( nStartRib, vRibs, vUsed, nGrpTmp, nType, nSrfTest)
if #tabUserLink > 0 then
-- se definisce UserLink aggiungo setto di partenza alla tabella
local dPar = EgtCurveParamAtPoint( nStartRib, EgtSP( vRibs[i]), 100 * GEO.EPS_SMALL)
local tRib = { nId = vRibs[i], bStart = true, bOn = true, dPar = dPar}
table.insert( tabUserLink, tRib)
-- assegno le info
local bCCW = false -- non posso conoscere a priori il verso del collegamento
local bLoopRib = false
local bSameSide = true
local sName = EgtGetName( vRibs[i])
AssignUserLinkInfo( tabUserLink, bCCW, bLoopRib, bSameSide, sName)
-- correggo orientamento del link
bCCW = FindRibsUserLinkDirection( tabUserLink[1].nId, tabUserLink[2].nId, vtSlicing)
for i = 1, #tabUserLink do
local nId = tabUserLink[i].nId
EgtSetInfo( nId, KEY_RIBS_USER_LINK_CCW, bCCW)
end
else
-- se non è UserLink lo rimuovo dalla tabella dei tratti utilizzati per controllarlo nelle iterazioni successive
vUsed[vRibs[i]] = nil
end
end
end
EgtErase( nGrpTmp)
end
-------------------------------------------------------------------
local function FindAssociatedHoledRib( vRibs, nCrv)
-- trovo setto di vRibs che poggia su nCrv
if not nCrv then return end
if not vRibs or #vRibs == 0 then return end
for i = 1, #vRibs do
-- verifico se ha un estremo sulla curva
local ptS = EgtSP( vRibs[i], GDB_ID.ROOT)
local dParS = EgtCurveParamAtPoint( nCrv, ptS, GEO.EPS_SMALL, GDB_RT.GLOB)
if dParS then
return i, true
else
local ptE = EgtEP( vRibs[i], GDB_ID.ROOT)
local dParE = EgtCurveParamAtPoint( nCrv, ptE, GEO.EPS_SMALL, GDB_RT.GLOB)
if dParE then
return i, false
end
end
end
return
end
-------------------------------------------------------------------
local function FindHoleCurve( pt, vLoopIds)
-- trovo indice della curva di vLoopIds a cui appartiene pt ( in globale)
if not vLoopIds then return end
for i = 1, #vLoopIds do
local dPar = EgtCurveParamAtPoint( vLoopIds[i], pt, GEO.EPS_SMALL, GDB_RT.GLOB)
if dPar then
return i
end
end
return
end
-------------------------------------------------------------------
local function ReorderHoledRibs( vRibs, tHoles, bInvertOrder)
local vUserLink = {} -- vettore con gli id dei tratti di UserLink
local tUserLink = {} -- chiave = setto, valore = true/false se userlink oppure no
for i = 1, #vRibs do
local bUserLink = EgtGetInfo( vRibs[i], KEY_RIBS_USER_LINK, 'b') or false
tUserLink[vRibs[i]] = bUserLink
if bUserLink then
table.insert( vUserLink, vRibs[i])
end
end
local nRelocatePosFirst = EgtIf( bInvertOrder, GDB_IN.AFTER, GDB_IN.BEFORE)
local nRelocatePos = EgtIf( bInvertOrder, GDB_IN.BEFORE, GDB_IN.AFTER)
local nIdx = 1
while nIdx <= #vUserLink do
local nTot = EgtGetInfo( vUserLink[nIdx], KEY_RIBS_USER_LINK_TOT, 'i')
local nFirst = vUserLink[nIdx]
local nLast = vUserLink[nIdx + nTot - 1]
if bInvertOrder then
-- i tratti di UserLink saranno ordinati in senso opposto
nFirst, nLast = nLast, nFirst
end
-- primo tratto di UserLink
local vAssRibs = tHoles[nFirst] or {}
for j = #vAssRibs, 1, -1 do
if not tUserLink[vAssRibs[j]] then
EgtRelocateGlob( vAssRibs[j], nFirst, nRelocatePosFirst)
end
end
-- altri tratti di UserLink
for k = 1, nTot - 1 do
local nCurrIdx = EgtIf( bInvertOrder, nIdx + nTot - 1 - k, nIdx + k)
local vAssRibs = tHoles[vUserLink[nCurrIdx]] or {}
for j = #vAssRibs, 1, -1 do
if not tUserLink[vAssRibs[j]] then
EgtRelocateGlob( vAssRibs[j], nLast, nRelocatePos)
end
end
end
-- passo al gruppo di UserLink successivo
nIdx = nIdx + nTot
end
end
-------------------------------------------------------------------
local function AdjustHoledRibs( nTrimmedRibsGrp)
local vRibs = EgtGetAllInGroup( nTrimmedRibsGrp)
if not vRibs then return end
-- recupero i loop della superficie del setto
local nLoopGrp = EgtGetFirstNameInGroup( s_nPartId, RIBS_LOOP_GRP)
-- individuo catena di setti che è stata interrotta dagli holes partendo dai setti con user link
local bHoles = false
local tHoles = {}
while #vRibs > 0 do
-- cerco il primo setto di tipo UserLink
local nRefRib
for i = 1, #vRibs do
local bUserLink = EgtGetInfo( vRibs[i], KEY_RIBS_USER_LINK, 'b') or false
if bUserLink then
nRefRib = vRibs[i]
table.remove( vRibs, i)
break
end
end
if not nRefRib then break end
local sName = EgtGetName( nRefRib)
-- verifico se è limitato da un hole
local nOrigSrfId = EgtGetInfo( nRefRib, KEY_ORIGINAL_SURF, 'i')
local vLoopIds = EgtGetNameInGroup( nLoopGrp, SURF_LOOP .. tostring( nOrigSrfId))
local ptS = EgtSP( nRefRib, GDB_ID.ROOT)
local ptE = EgtEP( nRefRib, GDB_ID.ROOT)
local nIdx = FindHoleCurve( ptS, vLoopIds)
local bStartOrig = true
if not nIdx then
nIdx = FindHoleCurve( ptE, vLoopIds)
bStartOrig = false
end
if nIdx then
tHoles[nRefRib] = {}
-- trovo tutti i setti associati
local nAssIdx, bStart = FindAssociatedHoledRib( vRibs, vLoopIds[nIdx])
while nAssIdx do
bHoles = true
local nCurrRib = vRibs[nAssIdx]
local ptRef = EgtIf( bStart, EgtEP( nCurrRib, GDB_ID.ROOT), EgtSP( nCurrRib, GDB_ID.ROOT))
local bUserLink = EgtGetInfo( nCurrRib, KEY_RIBS_USER_LINK, 'b') or false
if not bUserLink then
-- se non è coinvolto in altro user link assegno lo stesso orientamento e lo stesso nome
if bStartOrig == bStart then
EgtInvertCurve( nCurrRib)
UpdateInvertInfo( nCurrRib)
end
EgtSetName( nCurrRib, sName)
end
table.insert( tHoles[nRefRib], nCurrRib)
table.remove( vRibs, nAssIdx)
-- verifico se con l'altro estermo poggia su hole e trovo setto associato
local nIdx = FindHoleCurve( ptRef, vLoopIds)
nAssIdx, bStart = FindAssociatedHoledRib( vRibs, vLoopIds[nIdx])
end
end
end
-- se no holes esco
if not bHoles then return end
-- riordino
vRibs = EgtGetAllInGroup( nTrimmedRibsGrp)
local bInvertOrder = EgtGetInfo( vRibs[1], KEY_RIBS_INVERT_STRAND_ORDER, 'b') or false
ReorderHoledRibs( vRibs, tHoles, bInvertOrder)
-- gestione per eventuale InvertDirection
local bInvertDir = EgtGetInfo( vRibs[1], KEY_RIBS_INVERT_DIR, 'b') or false
if bInvertDir then
for nRib1, vAssRibs in pairs( tHoles) do
local nRib2 = vAssRibs[#vAssRibs]
if nRib2 then
-- se entrambi coinvolti in UserLink scambio le direzioni
local bUserLink1 = EgtGetInfo( nRib1, KEY_RIBS_USER_LINK, 'b') or false
local bUserLink2 = EgtGetInfo( nRib2, KEY_RIBS_USER_LINK, 'b') or false
if bUserLink1 and bUserLink2 then
local bInvert1 = EgtGetInfo( nRib1, KEY_INVERTED_CRV, 'b') or false
local bInvert2 = EgtGetInfo( nRib2, KEY_INVERTED_CRV, 'b') or false
if bInvert1 ~= bInvert2 then
EgtInvertCurve( nRib1)
UpdateInvertInfo( nRib1)
EgtInvertCurve( nRib2)
UpdateInvertInfo( nRib2)
end
end
-- scambio le info
SwapInfo( nRib1, nRib2, KEY_RIBS_USER_LINK, 'b', false)
SwapInfo( nRib1, nRib2, KEY_RIBS_USER_LINK_ORDER, 'i', 0)
SwapInfo( nRib1, nRib2, KEY_RIBS_USER_LINK_TOT, 'i', 0)
SwapInfo( nRib1, nRib2, KEY_RIBS_USER_LINK_CCW, 'b', false)
-- scambio la posizione
local nCopy = EgtCopyGlob( nRib2, nRib2, GDB_IN.AFTER)
EgtRelocateGlob( nRib2, nRib1, GDB_IN.AFTER)
EgtRelocateGlob( nRib1, nCopy, GDB_IN.AFTER)
EgtErase( nCopy)
end
end
end
end
-------------------------------------------------------------------
local function TrimRibs( vRibs, nRibsGrp, nSrf, dSrfOffs, vtSlicing)
-- costruisco le superfici con cui fare il trim grossolano dei setti
local nSrfInt = GDB_ID.NULL
local nSrfExt = GDB_ID.NULL
if nSrf ~= GDB_ID.NULL then
local bOk
bOk, _, nSrfInt = ComputeSurfOffset( nSrf, nRibsGrp, dSrfOffs, vtSlicing)
if not bOk then
EgtOutLog( 'Warning: coarse trim for internal ribs may be innacurate (layer '.. EgtNumToString( s_nCurrIdx) ..') - CalcPaths')
nSrfInt = EgtCopyGlob( nSrf, nRibsGrp)
end
bOk, _, nSrfExt = ComputeSurfOffset( nSrf, nRibsGrp, - dSrfOffs, vtSlicing)
if not bOk then
EgtOutLog( 'Warning: coarse trim for external ribs may be innacurate (layer '.. EgtNumToString( s_nCurrIdx) ..') - CalcPaths')
nSrfExt = EgtCopyGlob( nSrf, nRibsGrp)
end
end
-- trim dei setti
local nTrimmedRibsGrp = EgtGroup( nRibsGrp)
local tUserLink = {} -- tratti appartenenti a UserLink
local vSingleRibs = {} -- tratti singoli
for i = 1, #vRibs do
-- trim dei setti
local nType = EgtGetInfo( vRibs[i], KEY_RIBS_TYPE, 'i')
local nCopyRib = EgtCopyGlob( vRibs[i], nTrimmedRibsGrp)
local nCrv, nCnt
if nType == RIB_TYPE.INTERNAL or nType == RIB_TYPE.SUPPORT then
if EgtSurfFrChunkCount( nSrfInt) == 0 then
-- se la superficie non esiste, il setto deve essere cancellato
nCrv = nCopyRib
nCnt = 0
else
nCrv, nCnt = EgtTrimCurveWithRegion( nCopyRib, nSrfInt, true, true)
end
elseif nType == RIB_TYPE.EXTERNAL then
if EgtSurfFrChunkCount( nSrfExt) == 0 then
-- se la superficie non esiste il setto è valido
nCrv = nCopyRib
nCnt = 1
else
nCrv, nCnt = EgtTrimCurveWithRegion( nCopyRib, nSrfExt, false, true)
end
else
-- setto unbounded non va tagliato
nCrv = nCopyRib
nCnt = 1
end
-- se errore nel calcolare trim ( nCrv = nil) riprendo il setto originario
if not nCrv then
nCrv = nCopyRib
nCnt = 1
end
if nCnt == 0 then
-- il setto va eliminato
EgtErase( nCrv)
elseif nCnt == 1 then
-- tratto singolo
EgtSetInfo( nCrv, KEY_START_RIB, vRibs[i])
table.insert( vSingleRibs, nCrv)
EgtSetInfo( vRibs[i], KEY_ASSOCIATED_CRVS, {nCrv})
else
-- UserLink
tUserLink[vRibs[i]] = {}
local bCCW = FindRibsUserLinkDirection( nCrv, nCrv + 1, vtSlicing)
-- sistemo le info
for j = 0, nCnt - 1 do
EgtSetInfo( nCrv + j, KEY_START_RIB, vRibs[i])
EgtSetInfo( nCrv + j, KEY_RIBS_USER_LINK, 1)
EgtSetInfo( nCrv + j, KEY_RIBS_USER_LINK_ORDER, j)
EgtSetInfo( nCrv + j, KEY_RIBS_USER_LINK_TOT, nCnt)
EgtSetInfo( nCrv + j, KEY_RIBS_USER_LINK_CCW, bCCW)
-- se setto di partenza è chiuso è LoopRib
if EgtCurveIsClosed( vRibs[i]) then EgtSetInfo( nCrv + j, KEY_LOOP_RIB, 1) end
-- se ho solo due tratti allora il link è realizzato da un solo lato
if nCnt == 2 then EgtSetInfo( nCrv + j, KEY_RIBS_USER_LINK_SAME_SIDE, 1) end
table.insert( tUserLink[vRibs[i]], nCrv + j)
end
EgtSetInfo( vRibs[i], KEY_ASSOCIATED_CRVS, tUserLink[vRibs[i]])
end
end
-- verifico e sistemo UserLink
AdjustUserLinkRibs( tUserLink, vSingleRibs, vtSlicing, nSrfInt, nSrfExt, nRibsGrp)
-- verifico se necessari aggiustamenti per holes
AdjustHoledRibs( nTrimmedRibsGrp)
return nTrimmedRibsGrp
end
--------------------------------------------------------------------
local function ComputeRibsOrientedOffset( nRibsGrp, dStrand)
local nOffsGrp = EgtGroup( EgtGetParent( nRibsGrp))
local nCurrRib = EgtGetFirstNameInGroup( nRibsGrp, RIBS_CRV .. '*')
while nCurrRib do
-- recupero tutti i tratti appartenenti a quel setto (hanno lo stesso nome)
local sName = EgtGetName( nCurrRib)
local vIds = EgtGetNameInGroup( nRibsGrp, sName)
-- recupero i parametri del setto
local bInvert = EgtGetInfo( nCurrRib, KEY_RIBS_INVERT_DIR, 'b') or false
local bInvertOrder = EgtGetInfo( nCurrRib, KEY_RIBS_INVERT_STRAND_ORDER, 'b') or false
local nShellsNbr = EgtGetInfo( nCurrRib, KEY_RIBS_SHELLS_NBR, 'i')
local dOffs = ( nShellsNbr - 1) * dStrand / 2
-- offset di ogni tratto del setto
local vOffs = {}
local bPlusToMinus = false
for i = 1, #vIds do
local bUserLinked = EgtGetInfo( vIds[i], KEY_RIBS_USER_LINK, 'b') or false
local bCCW = EgtGetInfo( vIds[i], KEY_RIBS_USER_LINK_CCW, 'b') or false
local nLinkOrder = EgtGetInfo( vIds[i], KEY_RIBS_USER_LINK_ORDER, 'i') or 0
-- ordine di realizzazione degli offset
if not bUserLinked then
bPlusToMinus = false
else
if nLinkOrder == 0 then
-- determinato dal verso del collegamento
bPlusToMinus = EgtIf( bCCW, true, false)
else
bPlusToMinus = not bPlusToMinus
end
end
local vOffsRib = {}
for k = 0, nShellsNbr - 1 do
local dOffsCurr = dOffs - k * dStrand
local nNewId
if abs( dOffsCurr) < GEO.EPS_SMALL then
nNewId = EgtCopyGlob( vIds[i], nOffsGrp)
else
nNewId = EgtOffsetCurveAdv( vIds[i], EgtIf( bPlusToMinus, dOffsCurr, - dOffsCurr))
end
if nNewId then
EgtSetName( nNewId, sName)
EgtSetInfo( nNewId, KEY_TYPE, TYPE.RIB)
EgtSetInfo( nNewId, KEY_ORIGINAL_RIB, vIds[i])
EgtRelocateGlob( nNewId, nOffsGrp)
table.insert( vOffs, nNewId)
table.insert( vOffsRib, nNewId)
end
end
EgtSetInfo( vIds[i], KEY_ASSOCIATED_CRVS, vOffsRib)
end
-- ordinamento
if bInvertOrder then
for i = 1, #vOffs - 1 do
EgtRelocateGlob( vOffs[i], vOffs[#vOffs], GDB_IN.AFTER)
end
-- aggiorno il vettore con gli indici per rispettare nuovo ordinamento
vOffs = EgtGetNameInGroup( nOffsGrp, sName)
end
-- orientamento
local bInvertCrv = bInvert
for j = 1, #vOffs, nShellsNbr do
-- stabilisco orientamento del primo tratto del gruppo
local bUserLinked = EgtGetInfo( vOffs[j], KEY_RIBS_USER_LINK, 'b') or false
local nLinkOrder = EgtGetInfo( vOffs[j], KEY_RIBS_USER_LINK_ORDER, 'i') or 0
local nLinkTot = EgtGetInfo( vOffs[j], KEY_RIBS_USER_LINK_TOT, 'i') or 0
if not bUserLinked then
bInvertCrv = bInvert
else
if ( not bInvertOrder and nLinkOrder == 0) or ( bInvertOrder and nLinkOrder == nLinkTot - 1) then
bInvertCrv = bInvert
if ( nShellsNbr % 2 == 0 and ( not bInvertOrder or nLinkTot % 2 ~= 0)) or ( nShellsNbr % 2 ~= 0 and bInvertOrder) then
bInvertCrv = not bInvert
end
else
if nShellsNbr % 2 == 0 then
bInvertCrv = not bInvertCrv
end
end
end
-- inversione
for k = 0, nShellsNbr - 1 do
if ( bInvertCrv and k % 2 == 0) or ( not bInvertCrv and k % 2 ~= 0) then
EgtInvertCurve( vOffs[j + k])
UpdateInvertInfo( vOffs[j + k])
end
end
end
-- passo al setto successivo
nCurrRib = EgtGetNextName( vIds[#vIds], RIBS_CRV .. '*')
end
return nOffsGrp
end
--------------------------------------------------------------------
local function ComputeTrimSurfWithOverlapsForRibs( vIds, nSrfBase, nSrfExt, dOffs, dStrand, nGrp, vtSlicing)
-- per ogni tipologia e overlap creo le superfici con cui fare i trim
local tSurfOffs = {{}, {}, {}, {}}
for i = 1, #vIds do
local nOverlap = EgtGetInfo( vIds[i], KEY_RIBS_OVERLAP, 'i')
local nType = EgtGetInfo( vIds[i], KEY_RIBS_TYPE, 'i')
if not tSurfOffs[nType][nOverlap] then
if nType == RIB_TYPE.INTERNAL or nType == RIB_TYPE.SUPPORT then
if nSrfBase ~= GDB_ID.NULL then
local dNewOffs = nOverlap / 100 * dStrand
local bOk, bExists, nSrfOffs = ComputeSurfOffset( nSrfBase, nGrp, dNewOffs, vtSlicing)
if not bOk then
-- considero la superficie senza overlap corretto
EgtOutLog( 'Warning: rib without correct overlap (layer '.. EgtNumToString( s_nCurrIdx) ..') - CalcPaths')
nSrfOffs = EgtCopyGlob( nSrfBase, nGrp)
end
tSurfOffs[RIB_TYPE.INTERNAL][nOverlap] = nSrfOffs
tSurfOffs[RIB_TYPE.SUPPORT][nOverlap] = nSrfOffs
end
elseif nType == RIB_TYPE.EXTERNAL then
if nSrfExt ~= GDB_ID.NULL then
local dNewOffs = dOffs + ( 0.5 - nOverlap / 100) * dStrand
local bOk, bExists, nSrfOffs = ComputeSurfOffset( nSrfExt, nGrp, dNewOffs, vtSlicing)
if not bOk then
-- considero la superficie senza overlap corretto
EgtOutLog( 'Warning: rib without correct overlap (layer '.. EgtNumToString( s_nCurrIdx) ..') - CalcPaths')
nSrfOffs = EgtCopyGlob( nSrfExt, nGrp)
end
tSurfOffs[nType][nOverlap] = nSrfOffs
EgtSetName( nSrfOffs, TOT_SHELL_TRIM_SURF)
else
-- se la superficie non esiste, il setto è sicuramente esterno ( è analogo ad unbounded)
tSurfOffs[nType][nOverlap] = GDB_ID.NULL
end
else
tSurfOffs[nType][nOverlap] = GDB_ID.NULL
end
end
end
return tSurfOffs
end
--------------------------------------------------------------------
local function VerifyRibsIntersection( nRib1, nRib2, nType1, nType2, nSrf1, nSrf2, dStrand, nGrp, nOffsGrp)
-- setti interni/supporto ed esterni non si possono intersecare per definizione
if ( ( nType1 == RIB_TYPE.INTERNAL or nType1 == RIB_TYPE.SUPPORT) and nType2 == RIB_TYPE.EXTERNAL) or
( nType1 == RIB_TYPE.EXTERNAL and ( nType2 == RIB_TYPE.INTERNAL or nType2 == RIB_TYPE.SUPPORT)) then
return false
end
-- se hanno lo stesso nome derivano dalla stessa costolatura quindi non ha senso controllare intersezione
-- ( non vengono gestiti setti che si autointersecano)
if EgtGetName( nRib1) == EgtGetName( nRib2) then
return false
end
local bInters = false
local bForceCrv1Cut = false
-- porto le curve nel gruppo locale
local nCrv1 = EgtCopyGlob( nRib1, nGrp)
local nCrv2 = EgtCopyGlob( nRib2, nGrp)
-- verifico se si intersecano nel piano XY definito dal gruppo locale
local nId, nPntCnt, nCrvCnt = EgtCurveCurveInters( nCrv1, nCrv2, nGrp)
-- se si intersecano verifico se ho intersezioni valide
if nId then
-- scorro tutti i punti di intersezione trovati
for i = 0, nPntCnt - 1 do
local nPtId = nId + i
-- verifico se valida
if nType1 == RIB_TYPE.UNBOUNDED and nType2 == RIB_TYPE.UNBOUNDED then
-- nel caso unbounded l'intersezione può essere ovunque
bInters = true
elseif nType1 == RIB_TYPE.EXTERNAL or nType2 == RIB_TYPE.EXTERNAL then
if nSrf2 then
-- l'intersezione deve essere esterna
if EgtSurfFrTestExternal( nSrf2, nPtId) then bInters = true end
else
-- se la surf non esiste l'intersezione è sicuramente esterna
bInters = true
end
else
-- se uno dei due è interno o supporto l'intersezione deve essere interna
if nSrf1 and not EgtSurfFrTestExternal( nSrf1, nPtId) then bInters = true end
end
-- se valida verifico se forza il taglio sulla curva 1
if bInters then
local ptInt = EgtSP( nPtId, GDB_ID.ROOT)
local dPar1 = EgtCurveParamAtPoint( nCrv1, ptInt, GEO.EPS_SMALL, GDB_RT.GLOB)
local dPar2 = EgtCurveParamAtPoint( nCrv2, ptInt, GEO.EPS_SMALL, GDB_RT.GLOB)
local _, dParE1 = EgtCurveDomain( nCrv1)
local _, dParE2 = EgtCurveDomain( nCrv2)
local bCrv1OnExtr = ( dPar1 < 10 * GEO.EPS_SMALL or abs( dPar1 - dParE1) < 10 * GEO.EPS_SMALL)
local bCrv2OnExtr = ( dPar2 < 10 * GEO.EPS_SMALL or abs( dPar2 - dParE2) < 10 * GEO.EPS_SMALL)
bForceCrv1Cut = ( bCrv1OnExtr and not bCrv2OnExtr)
if bForceCrv1Cut then
return bInters, bForceCrv1Cut -- true, true
end
end
end
return bInters, bForceCrv1Cut -- true/false, false
else
-- se non si intersecano, verifico se si intersecano i loro offset
local vOffs1 = EgtGetNameInGroup( nOffsGrp, EgtGetName( nCrv1)) or {}
local vOffs2 = EgtGetNameInGroup( nOffsGrp, EgtGetName( nCrv2)) or {}
for i = 1, #vOffs1 do
local nSrfOffs1 = EgtSurfFrFatCurve( nGrp, vOffs1[i], 0.5 * dStrand, false)
if nSrfOffs1 then
for j = 1, #vOffs2 do
-- verifico se intersezione
local nRes = EgtCurveWithRegionClassify( vOffs2[j], nSrfOffs1)
if nRes == GDB_CRC.IN or nRes == GDB_CRC.INTERS then
bInters = true
break
end
end
if bInters then break end
end
end
return bInters, bForceCrv1Cut -- true, false
end
end
---------------------------------------------------------------------------------
-- Funzione che sistema le intersezioni fra costolature nel caso generico
local function AdjustRibsOffsetForIntersection( nCrv1, nCrv2, LayerParams, nOffsGrp, nLoopGrp, tSurfOffs, nType2)
-- calcolo la superficie della curva principale ( nCrv1) da usare per trim
local nShells = EgtGetInfo( nCrv1, KEY_RIBS_SHELLS_NBR, 'i')
local nOverlap = EgtGetInfo( nCrv2, KEY_RIBS_OVERLAP, 'i')
local dOffs = ( nShells - 1) * LayerParams.dStrand / 2
local nSrf = EgtSurfFrFatCurve( nOffsGrp, nCrv1, dOffs + ( 1 - nOverlap / 100) * LayerParams.dStrand, false)
if not nSrf then return end
-- trim degli offset della curva secondaria ( nCrv2)
local vOffs2 = EgtGetNameInGroup( nOffsGrp, EgtGetName( nCrv2)) or {}
for i = 1, #vOffs2 do
local nId, nCnt = EgtTrimCurveWithRegion( vOffs2[i], nSrf, false, true)
-- se setto chiuso verifico se primo e ultimo tratto possono essere uniti
if EgtCurveIsClosed( nCrv2) then
if nCnt > 1 and AreSamePointApprox( EgtEP( nId + nCnt - 1), EgtSP( nId)) then
EgtRelocateGlob( nId + nCnt - 1, nId, GDB_IN.AFTER)
EgtAddCurveCompoCurve( nId + nCnt - 1, nId)
EgtChangeId( nId + nCnt - 1, nId)
nCnt = nCnt - 1
end
end
-- aggiorno ordine di split copiandolo da nCrv2
for j = nId, nId + nCnt - 1 do
CopyInfo( nCrv2, j, KEY_SPLIT_ORDER, 'i')
end
end
-- salvo i loop da usare nel toolpath per ingressi e uscite
local nSrfRef
-- recupero la superficie di bordo con lo stesso overlap
local nSrfTrim = tSurfOffs[nType2][nOverlap]
if nSrfTrim and nSrfTrim ~= GDB_ID.NULL then
nSrfRef = EgtCopyGlob( nSrfTrim, nLoopGrp)
if nType2 == RIB_TYPE.INTERNAL then
EgtSurfFrSubtract( nSrfRef, nSrf)
elseif nType2 == RIB_TYPE.EXTERNAL then
EgtSurfFrAdd( nSrfRef, nSrf)
end
EgtErase( nSrf)
else
EgtInvertSurf( nSrf)
nSrfRef = nSrf
end
-- estraggo i loop
local nChunks = EgtSurfFrChunkCount( nSrfRef)
for i = 0, nChunks - 1 do
local nRes, nCnt = EgtExtractSurfFrChunkLoops( nSrfRef, i, nLoopGrp)
for j = nRes, nRes + nCnt - 1 do
EgtSetName( j, SURF_LOOP)
end
end
EgtErase( nSrfRef)
end
--------------------------------------------------------------------
-- Funzione che sistema le intersezioni fra costolature nel caso di 2 passate
local function AdjustRibsOffsetForIntersection2Shells( nCrv1, nCrv2, LayerParams, nOffsGrp)
-- costruisco le superfici da usare per trim
local nSrf1 = EgtSurfFrFatCurve( nOffsGrp, nCrv1, LayerParams.dStrand / 2, false)
local vtN1 = EgtSurfFrNormVersor( nSrf1, GDB_ID.ROOT)
if LayerParams.vtSlicing * vtN1 < 0 then
EgtInvertSurf( nSrf1)
end
local nSrf2 = EgtSurfFrFatCurve( nOffsGrp, nCrv2, LayerParams.dStrand / 2, false)
local vtN2 = EgtSurfFrNormVersor( nSrf2, GDB_ID.ROOT)
if LayerParams.vtSlicing * vtN2 < 0 then
EgtInvertSurf( nSrf2)
end
-- trim degli offset di nCrv1
local vOffs1 = EgtGetNameInGroup( nOffsGrp, EgtGetName( nCrv1)) or {}
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)) or {}
for i = 1, #vOffs2 do
local nId, nCnt = EgtTrimCurveWithRegion( vOffs2[i], nSrf1, false, true)
end
EgtErase( nSrf1)
EgtErase( nSrf2)
end
------------------------------------------------------------------
local function UpdateSplitOrder( nCrv, tInters, nOffsGrp)
local nOrder = EgtGetInfo( nCrv, KEY_SPLIT_ORDER, 'i') or 0
local nNewOrder = nOrder + 1
-- aggiorno tutte le curve che dipendono da nCrv
if tInters[nCrv] then
for i = 1, #tInters[nCrv] do
local nOldOrder = EgtGetInfo( tInters[nCrv][i], KEY_SPLIT_ORDER, 'i')
if nOldOrder < nNewOrder then
EgtSetInfo( tInters[nCrv][i], KEY_SPLIT_ORDER, nNewOrder)
-- aggiorno i suoi offset
local vOffs = EgtGetNameInGroup( nOffsGrp, EgtGetName( tInters[nCrv][i]))
for j = 1, #vOffs do
EgtSetInfo( vOffs[j], KEY_SPLIT_ORDER, nNewOrder)
end
-- aggiorno eventuali dipendenze
UpdateSplitOrder( tInters[nCrv][i], tInters, nOffsGrp)
end
end
end
end
---------------------------------------------------------------------------------
local function HandleRibsIntersections( nRibsGrp, LayerParams, nOffsGrp, nRibsPathGrp, nLoopGrp, bAllTwoStrands, vTypeSequence, tSurfOffs)
local bSpecialCase = false
local vRibsIds = EgtGetNameInGroup( nRibsGrp, RIBS_CRV .. '*')
-- copio gli offset delle costolature nel RibsPathGrp
local nCrvGrp = EgtGetParent( nRibsPathGrp)
local vOffsRib = EgtGetAllInGroup( nOffsGrp)
for i = 1, #vOffsRib do
EgtCopyGlob( vOffsRib[i], nRibsPathGrp)
end
-- creo un gruppo con frame locale per calcolare le intersezioni ( è il piano XY locale dove calcolare intersezioni)
local frLoc = Frame3d( ORIG(), LayerParams.vtSlicing)
local nGrpTmp = EgtGroup( nRibsGrp, frLoc, GDB_RT.GLOB)
-- calcolo le regioni nella quali ha senso considerare l'intersezione
local nSrfOffs1, nSrfOffs2
local bOk, bExists
local nSrf1 = EgtGetFirstNameInGroup( nCrvGrp, TOT_SHELL_TRIM_SURF) or GDB_ID.NULL
if nSrf1 ~= GDB_ID.NULL then
bOk, bExists, nSrfOffs1 = ComputeSurfOffset( nSrf1, nCrvGrp, 2 * LayerParams.dStrand, LayerParams.vtSlicing)
if not bOk or not bExists then
nSrfOffs1 = EgtCopyGlob( nSrf1, nCrvGrp)
end
end
local nSrf2 = EgtGetFirstNameInGroup( nCrvGrp, LAYER_SRF) or GDB_ID.NULL
if nSrf2 ~= GDB_ID.NULL then
bOk, bExists, nSrfOffs2 = ComputeSurfOffset( nSrf2, nCrvGrp, - 2 * LayerParams.dStrand, LayerParams.vtSlicing)
if not bOk or not bExists then
nSrfOffs2 = EgtCopyGlob( nSrf2, nCrvGrp)
end
end
local bInters = false
local vSplit = {}
local tInters = {} -- tabella che tiene traccia delle intersezioni trovate
for i = 1, #vRibsIds do
local nType1 = EgtGetInfo( vRibsIds[i], KEY_RIBS_TYPE, 'i')
-- verifico se interseca uno dei setti successivi
for j = i + 1, #vRibsIds do
local nType2 = EgtGetInfo( vRibsIds[j], KEY_RIBS_TYPE, 'i')
local bRibInters, bForceCrv1Cut = VerifyRibsIntersection( vRibsIds[i], vRibsIds[j], nType1, nType2, nSrfOffs1, nSrfOffs2, LayerParams.dStrand, nGrpTmp, nOffsGrp)
if bRibInters then
bInters = true
local nCrv1 = vRibsIds[i] -- curva principale che non viene tagliata
local nCrv2 = vRibsIds[j] -- curve secondaria da modificare
local nSplitOrder1 = EgtGetInfo( nCrv1, KEY_SPLIT_ORDER, 'i') or 0
local nSplitOrder2 = EgtGetInfo( nCrv2, KEY_SPLIT_ORDER, 'i') or 0
if bForceCrv1Cut then
nCrv1, nCrv2 = nCrv2, nCrv1
nSplitOrder1, nSplitOrder2 = nSplitOrder2, nSplitOrder1
else
-- se stessa tipologia taglio il setto già splittato più volte, altrimenti taglio il setto che viene realizzato successivamente
if ( nType1 == nType2 and nSplitOrder1 > nSplitOrder2) or
( nType1 ~= nType2 and vTypeSequence[nType1] > vTypeSequence[nType2]) then
nCrv1, nCrv2 = nCrv2, nCrv1
nSplitOrder1, nSplitOrder2 = nSplitOrder2, nSplitOrder1
end
end
-- aggiorno tabella delle intersezioni
if tInters[nCrv1] then
table.insert( tInters[nCrv1], nCrv2)
else
tInters[nCrv1] = {nCrv2}
end
-- aggiorno ordine di split
if nSplitOrder2 < nSplitOrder1 + 1 then
EgtSetInfo( nCrv2, KEY_SPLIT_ORDER, nSplitOrder1 + 1)
UpdateSplitOrder( nCrv2, tInters, nRibsPathGrp)
end
if bAllTwoStrands and ( nType1 == nType2) then
-- nel caso di 2 passate e stessa tipologia gestione speciale per creare unico percorso
AdjustRibsOffsetForIntersection2Shells( nCrv1, nCrv2, LayerParams, nRibsPathGrp)
bSpecialCase = true
else
AdjustRibsOffsetForIntersection( nCrv1, nCrv2, LayerParams, nRibsPathGrp, nLoopGrp, tSurfOffs, nType2)
end
end
end
end
EgtErase( nSrfOffs1)
EgtErase( nSrfOffs2)
EgtErase( nGrpTmp)
return bInters, bSpecialCase
end
---------------------------------------------------------------------
local function ReorderSplitRibs( vIds, dStrand, bParamInvertOrder)
-- individuo i setti che derivano da uno stesso pezzo di costolatura
local tabRibs = {}
for i = 1, #vIds do
local nOrigId = EgtGetInfo( vIds[i], KEY_ORIGINAL_RIB, 'i')
if tabRibs[nOrigId] then
table.insert( tabRibs[nOrigId], vIds[i])
else
tabRibs[nOrigId] = { vIds[i]}
end
end
local tUserLinkSameSide = {}
for k, tabVal in pairs( tabRibs) do
-- verifico se split dopo intersezione con altro setto
local nSplitOrder = EgtGetInfo( tabVal[1], KEY_SPLIT_ORDER, 'i') or 0
-- verifico se split dopo aver fatto il trim con la superficie
local nStartRib = EgtGetInfo( tabVal[1], KEY_START_RIB, 'i')
local bSplitAfterTrim = EgtGetInfo( nStartRib, KEY_SPLIT_AFTER_TRIM, 'b') or false
if nSplitOrder > 0 or bSplitAfterTrim then
-- caso di setti splittati
local nShells = EgtGetInfo( tabVal[1], KEY_RIBS_SHELLS_NBR, 'i')
if nShells == 1 then
-- non è necessario il riordino, associo splitId diversi ad ogni tratto per gestire correttamente il link nel CalcToolPath
for i = 1, #tabVal do
EgtSetInfo( tabVal[i], KEY_SPLIT_ID, i)
end
else
-- associo le curve dello split
local tAssociatedRibs = {}
while #tabVal > 0 do
local nCurrId = tabVal[1]
table.remove( tabVal, 1)
table.insert( tAssociatedRibs, { nCurrId})
local bCurrSplitAfterTrim = EgtGetInfo( nCurrId, KEY_SPLIT_AFTER_TRIM, 'b') or false
while nCurrId do
local ptCurr = EgtMP( nCurrId)
bFound = false
for j = 1, #tabVal do
local dDist1 = EgtPointCurveDist( ptCurr, tabVal[j])
local dDist2 = EgtPointCurveDist( EgtMP( tabVal[j]), nCurrId)
if dDist1 < dStrand + 10 * GEO.EPS_SMALL or dDist2 < dStrand + 10 * GEO.EPS_SMALL then
-- verifico nel caso di setti splittati dopo il trim che siano compatibili
local bUserLink = EgtGetInfo( tabVal[j], KEY_RIBS_USER_LINK, 'b') or false
local bSplitAfterTrim = EgtGetInfo( tabVal[j], KEY_SPLIT_AFTER_TRIM, 'b') or false
if bSplitAfterTrim ~= bCurrSplitAfterTrim then
if not bCurrSplitAfterTrim and bSplitAfterTrim then
local nOrd = EgtGetInfo( tabVal[j], KEY_SPLIT_AFTER_TRIM_ORDER, 'i')
if nOrd == 0 then
bFound = true
end
end
if bCurrSplitAfterTrim then
local nOrd = EgtGetInfo( nCurrId, KEY_SPLIT_AFTER_TRIM_ORDER, 'i')
local nTot = EgtGetInfo( nCurrId, KEY_SPLIT_AFTER_TRIM_TOT, 'i')
if nOrd == nTot - 1 then
bFound = true
end
end
else
bFound = true
end
if bFound then
EgtRelocateGlob( tabVal[j], nCurrId, GDB_IN.AFTER)
nCurrId = tabVal[j]
bCurrSplitAfterTrim = bSplitAfterTrim
table.remove( tabVal, j)
table.insert( tAssociatedRibs[#tAssociatedRibs], nCurrId)
break
end
end
end
if not bFound then
nCurrId = nil
end
end
end
-- assegno splitid per gestire correttamente il link nel CalcToolPath
for i = 1, #tAssociatedRibs do
for j = 1, #tAssociatedRibs[i] do
EgtSetInfo( tAssociatedRibs[i][j], KEY_SPLIT_ID, i)
end
end
-- modifiche per preservare i link definiti dall'utente
local bUserLink = EgtGetInfo( tAssociatedRibs[1][1], KEY_RIBS_USER_LINK, 'b') or false
if bUserLink and nShells % 2 == 0 then
local bSameSide = EgtGetInfo( tAssociatedRibs[1][1], KEY_RIBS_USER_LINK_SAME_SIDE, 'b') or false
local nLinkOrder = EgtGetInfo( tAssociatedRibs[1][1], KEY_RIBS_USER_LINK_ORDER, 'i') or 0
local nTotParts = EgtGetInfo( tAssociatedRibs[1][1], KEY_RIBS_USER_LINK_TOT, 'i') or 1
local bInvertOrder = EgtGetInfo( tAssociatedRibs[1][1], KEY_RIBS_INVERT_STRAND_ORDER, 'b') or false
if bSameSide and nTotParts > 2 then
-- salvo gli id che andaranno collegati nella tabella tUserLinkSameSide
local sName = EgtGetName( tAssociatedRibs[1][1])
-- eventuale creazione della voce nella tabella
if not tUserLinkSameSide[sName] then
tUserLinkSameSide[sName] = {}
end
for i = 1, #tAssociatedRibs[1] do
table.insert( tUserLinkSameSide[sName], tAssociatedRibs[1][i])
end
else
-- ordinamento
if ( nTotParts % 2 == 0 and bInvertOrder and nLinkOrder % 2 ~= 0 ) or
( nTotParts % 2 == 0 and not bInvertOrder and nLinkOrder % 2 == 0) or
( nTotParts % 2 ~= 0 and nLinkOrder % 2 == 0) then
local vLastGrp = tAssociatedRibs[#tAssociatedRibs]
local nPrevId = vLastGrp[#vLastGrp]
for i = #tAssociatedRibs - 1, 1, -1 do
for j = 1, #tAssociatedRibs[i] do
local nCurrId = tAssociatedRibs[i][j]
EgtRelocateGlob( nCurrId, nPrevId, GDB_IN.AFTER)
nPrevId = nCurrId
end
end
end
-- direzione
if ( nTotParts % 2 == 0 and nLinkOrder > 0 and nLinkOrder < nTotParts - 1) or
( nTotParts % 2 ~= 0 and not bInvertOrder and nLinkOrder > 0) or
( nTotParts % 2 ~= 0 and bInvertOrder and nLinkOrder < nTotParts - 1) then
local vLastGrp = tAssociatedRibs[#tAssociatedRibs]
for j = 1, #vLastGrp do
EgtInvertCurve( vLastGrp[j])
UpdateInvertInfo( vLastGrp[j])
end
end
end
end
end
end
end
for k, vRibs in pairs( tUserLinkSameSide) do
table.sort( vRibs)
for i = 2, #vRibs do
EgtRelocateGlob( vRibs[i], vRibs[i-1], GDB_IN.AFTER)
end
end
end
--------------------------------------------------------------------
local function ShortestPathForRibs( vRibs, nGrp, bInvertOrder)
if not vRibs or #vRibs == 0 then return end
-- divido per gruppi di setti ( i gruppi sono identificati dallo stesso nome)
local tabRibs = {}
local sPrevName = ""
for i = 1, #vRibs do
local sName = EgtGetName( vRibs[i])
if sName == sPrevName then
table.insert( tabRibs[#tabRibs], vRibs[i])
else
table.insert( tabRibs, {vRibs[i]})
end
sPrevName = sName
end
-- stabilisco l'ordine di realizzazione dei gruppi di setti
local vOrd
if #tabRibs == 1 then
-- se un solo gruppo ordinamento banale
vOrd = {1}
else
-- se più gruppi ordinamento con shortest path
EgtSpInit()
for i = 1, #tabRibs do
local ptS = EgtSP( tabRibs[i][1], GDB_ID.ROOT)
local ptE = EgtEP( tabRibs[i][#tabRibs[i]], GDB_ID.ROOT)
EgtSpAddPoint( ptS:getX(), ptS:getY(), ptS:getZ(), 0, 0, ptE:getX(), ptE:getY(), ptE:getZ(), 0, 0)
end
vOrd = EgtSpCalculate( SHP_TY.OPEN)
EgtSpTerminate()
end
-- creo il vettore con i setti ordinati
local vIds = {}
local nStart = EgtIf( bInvertOrder, #vOrd, 1)
local nEnd = EgtIf( bInvertOrder, 1, #vOrd)
local nStep = EgtIf( bInvertOrder, -1, 1)
for i = nStart, nEnd, nStep do
local vCurrRibs = tabRibs[vOrd[i]]
for j = 1, #vCurrRibs do
table.insert( vIds, vCurrRibs[j])
end
end
EgtRelocateGlob( vIds[1], nGrp, GDB_IN.LAST_SON)
for i = 2, #vIds do
EgtRelocateGlob( vIds[i], vIds[i-1], GDB_IN.AFTER)
end
end
--------------------------------------------------------------------
local function ReorderRibs( nGrp, bInvertOrder, dStrand)
local vIds = EgtGetNameInGroup( nGrp, RIBS_CRV .. '*')
if not vIds or #vIds == 0 then return end
-- riordino setti splittati
ReorderSplitRibs( vIds, dStrand, bInvertOrder)
-- aggiorno gli id con il nuovo ordinamento
vIds = EgtGetNameInGroup( nGrp, RIBS_CRV .. '*')
-- raggruppo per tipologia
local tRibs = {{}, {}, {}, {}}
for i = 1, #vIds do
local nType = EgtGetInfo( vIds[i], KEY_RIBS_TYPE, 'i')
table.insert( tRibs[nType], vIds[i])
end
-- riordino ogni tipologia
for j = 1, 4 do
local vIds = tRibs[j]
-- raggruppo in base allo split order
local tSplitOrder = {}
local nMaxSplitOrder = 0
for i = 1, #vIds do
local nSplitOrder = EgtGetInfo( vIds[i], KEY_SPLIT_ORDER, 'i') or 0
-- eventuale aggiornamento del max split order
if nSplitOrder > nMaxSplitOrder then nMaxSplitOrder = nSplitOrder end
-- inserisco nella tabella
if not tSplitOrder[nSplitOrder] then
tSplitOrder[nSplitOrder]= {vIds[i]}
else
table.insert( tSplitOrder[nSplitOrder], vIds[i])
end
end
-- riordino ogni ordine di split con shortest path
for k = 0, nMaxSplitOrder do
ShortestPathForRibs( tSplitOrder[k], nGrp, bInvertOrder)
end
end
end
--------------------------------------------------------------------------------------------
local function ReassignInfo( nCrv, nCnt, vOrig)
for nId = nCrv, nCrv + nCnt - 1 do
local ptS = EgtSP( nId)
local ptE = EgtEP( nId)
EgtSetInfo( nId, KEY_TYPE, TYPE.RIB)
if EgtCurveIsClosed( nId) then
EgtSetInfo( nId, KEY_CLOSED_CRV, 1)
end
local bStart = false
local bEnd = false
while not bStart and not bEnd do
-- scorro le curve originarie per capire da quali deriva
for i = 1, #vOrig do
local ptSOrig = EgtSP( vOrig[i])
local ptEOrig = EgtEP( vOrig[i])
-- verifico se corrisponde al suo start
if AreSamePointApprox( ptS, ptSOrig) or AreSamePointApprox( ptS, ptEOrig) then
CopyInfo( vOrig[i], nId, KEY_RIBS_LEAD_IN_INVERT, 'b')
CopyInfo( vOrig[i], nId, KEY_RIBS_LEAD_IN_LEN, 'd')
CopyInfo( vOrig[i], nId, KEY_ASSOCIATED_SURF, 'i')
CopyInfo( vOrig[i], nId, KEY_RIBS_OVERLAP, 'i')
CopyInfo( vOrig[i], nId, KEY_RIBS_TYPE, 'i')
CopyInfo( vOrig[i], nId, KEY_RIBS_LINK, 'b')
bStart = true
end
-- verifico se corrisponde al suo end
if AreSamePointApprox( ptE, ptSOrig) or AreSamePointApprox( ptE, ptEOrig) then
CopyInfo( vOrig[i], nId, KEY_RIBS_LEAD_OUT_INVERT, 'b')
CopyInfo( vOrig[i], nId, KEY_RIBS_LEAD_OUT_LEN, 'd')
CopyInfo( vOrig[i], nId, KEY_RIBS_LEAD_OUT_COASTING, 'd')
CopyInfo( vOrig[i], nId, KEY_RIBS_LEAD_OUT_WIPE, 'd')
CopyInfo( vOrig[i], nId, KEY_RIBS_LEAD_OUT_WIPE_DIR, 'd')
bEnd = true
end
end
end
end
-- dopo aver salvato le info è inutile conservare le curve originali
for i = 1, #vOrig do
EgtErase( vOrig[i])
end
end
---------------------------------------------------------------------------------------------
-- Funzione che riordina le costolature nel caso di intersezioni e 2 passate
local function ReorderRibsInters2Shells( nOffsGrp, dStrand, bInvertOrder)
local vOffs = {}
local vClosed = {}
local nId = EgtGetFirstNameInGroup( nOffsGrp, RIBS_CRV .. '*')
while nId do
if EgtCurveIsClosed( nId) then
table.insert( vClosed, nId)
else
table.insert( vOffs, nId)
end
nId = EgtGetNextName( nId, RIBS_CRV .. '*')
end
local k = 0 -- indice da utilizzare per i nomi
-- gestione delle curve chiuse
if #vClosed > 0 then
k = k + 1
local sPrevName = EgtGetName( vClosed[1])
EgtSetName( vClosed[1], RIBS_CRV .. tostring( k))
for i = 2, #vClosed do
local sCurrName = EgtGetName( vClosed[i])
-- se setto diverso aggiorno il nome
if sCurrName ~= sPrevName then
k = k + 1
end
EgtSetName( vClosed[i], RIBS_CRV .. tostring( k))
sPrevName = sCurrName
end
end
-- gestione delle curve aperte
-- copio le curve originali ( per recuperarne le info)
local vCopy = {}
for i = 1, #vOffs do
local nNewId = EgtCopy( vOffs[i], nOffsGrp)
table.insert( vCopy, nNewId)
end
-- concateno le curve
local nCrv, nCnt = EgtCurveCompoByChain( nOffsGrp, vOffs, ORIG())
local vIds = {}
for i = nCrv, nCrv + nCnt - 1 do
table.insert( vIds, i)
end
-- recupero le info dalle curve originali
ReassignInfo( nCrv, nCnt, vCopy)
while #vIds > 0 do
k = k + 1
-- prendo la prima tra le curve a disposizione
nCurrCrv = vIds[1]
table.remove( vIds, 1)
EgtSetName( nCurrCrv, RIBS_CRV .. tostring(k))
local pt = EgtEP( nCurrCrv)
local _, dParE = EgtCurveDomain( nCurrCrv)
local nCnt = 0
-- scorro alla ricerca di una curva che posso collegare alla corrente
while nCurrCrv do
local nCurrType = EgtGetInfo( nCurrCrv, KEY_RIBS_TYPE, 'i')
local bFound = false
for j = 1, #vIds do
local nType = EgtGetInfo( vIds[j], KEY_RIBS_TYPE, 'i')
if vIds[j] ~= nCrv and not EgtCurveIsClosed(vIds[j]) and nCurrType == nType then
-- verifico se il collegamento è possibile
local bAdd = false
local bInvert = false
local dDist, _, dParMinDist = EgtPointCurveDist( pt, vIds[j])
if dDist < dStrand + 10 * GEO.EPS_SMALL then
-- controllo che sia vicino ad uno degli estremi
local dParS, dParE = EgtCurveDomain( vIds[j])
if abs( dParMinDist - dParS) < 500 * GEO.EPS_SMALL then
bAdd = true
elseif abs( dParMinDist - dParE) < 500 * GEO.EPS_SMALL then
bAdd = true
-- è se necessaria inversione di vIds[j]
bInvert = true
end
end
if not bAdd then
-- check sullo start point di vIds[j]
local dDist, _, dParMinDist = EgtPointCurveDist( EgtSP( vIds[j]), nCurrCrv)
if dDist < dStrand + 10 * GEO.EPS_SMALL then
bInvert = false
-- controllo sia vicino all'end point della curva corrente
if dParE - dParMinDist < 500 * GEO.EPS_SMALL then
bAdd = true
-- altrimenti può essere vicino allo start
elseif dParMinDist < 500 * GEO.EPS_SMALL and nCnt == 0 then
bAdd = true
EgtInvertCurve( nCurrCrv)
end
end
-- se non è aggiunto check con end point di vIds[j]
if not bAdd then
local dDist, _, dParMinDist = EgtPointCurveDist( EgtEP( vIds[j]), nCurrCrv)
if dDist < dStrand + 10 * GEO.EPS_SMALL then
bInvert = true
if dParE - dParMinDist < 500 * GEO.EPS_SMALL then
bAdd = true
elseif dParMinDist < 500 * GEO.EPS_SMALL and nCnt == 0 then
bAdd = true
EgtInvertCurve( nCurrCrv)
end
end
end
end
if bAdd then
bFound = true
nCnt = nCnt + 1
EgtRelocateGlob( vIds[j], nCurrCrv, GDB_IN.AFTER)
EgtSetName( vIds[j], RIBS_CRV .. tostring( k))
-- eventuale inversione della curva
if bInvert then EgtInvertCurve( vIds[j]) end
-- aggiorno per collegamento successivo
pt = EgtEP( vIds[j])
_, dParE = EgtCurveDomain( vIds[j])
nCurrCrv = vIds[j]
-- elimino la curva dal vettore di curve da considerare
table.remove( vIds, j)
break
end
end
end
-- se non ho più curve da collegare
if not bFound and nCnt == 0 then
-- se era la prima curva faccio un tentativo invertendola
nCnt = 1
EgtInvertCurve( nCurrCrv)
pt = EgtEP( nCurrCrv)
elseif not bFound then
nCurrCrv = nil
end
end
end
-- eventuale inversione ordinamento
if bInvertOrder then
local vRibs = EgtGetNameInGroup( nOffsGrp, RIBS_CRV .. '*')
for j = #vRibs, 1, -1 do
-- inverto direzione curve per mantenere concatenamento
EgtInvertCurve( vRibs[j])
EgtRelocateGlob( vRibs[j], nOffsGrp, GDB_IN.LAST_SON)
end
end
end
-------------------------------------------------------------------
local function CalcRibsPaths( nSliceGrp, nRibsGrp, LayerParams, vPtStart)
-- stabilisco ordine di realizzazione delle varie tipologie
local vTypeSequence = {}
for i = 1, #LayerParams.vPrintOrder do
if LayerParams.vPrintOrder[i] == PRINT_ELEMENT.RIB_UNBOUNDED then
vTypeSequence[RIB_TYPE.UNBOUNDED] = i
elseif LayerParams.vPrintOrder[i] == PRINT_ELEMENT.RIB_INTERNAL then
vTypeSequence[RIB_TYPE.INTERNAL] = i
elseif LayerParams.vPrintOrder[i] == PRINT_ELEMENT.RIB_EXTERNAL then
vTypeSequence[RIB_TYPE.EXTERNAL] = i
elseif LayerParams.vPrintOrder[i] == PRINT_ELEMENT.RIB_SUPPORT then
vTypeSequence[RIB_TYPE.SUPPORT] = i
end
end
local vOrigRibs = EgtGetNameInGroup( nRibsGrp, RIBS_CRV .. '*')
-- verifico se tutte le costolature vengono fatte con 2 passate
local bAllTwoStrands = true
for i = 1, #vOrigRibs do
local nStrand = EgtGetInfo( vOrigRibs[i], KEY_RIBS_SHELLS_NBR, 'i')
if nStrand ~= 2 then
bAllTwoStrands = false
break
end
end
-- verifico se posso ignorare eventuali buchi nei setti
VerifyRibsHoles( vOrigRibs, LayerParams.dStrand)
-- scorro i gruppi di curve
local nCrvGrp = EgtGetFirstNameInGroup( nSliceGrp, CONTOUR_GRP .. '*')
while nCrvGrp do
-- creo o svuoto il gruppo
local nRibsPathGrp = EgtGetFirstNameInGroup( nCrvGrp, RIBS_GRP)
if not nRibsPathGrp then
nRibsPathGrp = EgtGroup( nCrvGrp)
EgtSetName( nRibsPathGrp, RIBS_GRP)
EgtSetStatus( nRibsPathGrp, GDB_ST.OFF)
else
EgtEmptyGroup( nRibsPathGrp)
end
-- recupero le superfici
local nSrfBase = EgtGetFirstNameInGroup( nCrvGrp, TOT_SHELL_TRIM_SURF) or GDB_ID.NULL
local nSrfExt = EgtGetFirstNameInGroup( nCrvGrp, LAYER_SRF) or GDB_ID.NULL
-- trim grossolano dei setti
local nTrimGrp = TrimRibs( vOrigRibs, nRibsGrp, nSrfExt, LayerParams.dOffs - LayerParams.dStrand / 2, LayerParams.vtSlicing)
-- calcolo offset orientati
local nOffsGrp = ComputeRibsOrientedOffset( nTrimGrp, LayerParams.dStrand)
-- creo le superfici con cui fare i trim corretti
local tSurfOffs = ComputeTrimSurfWithOverlapsForRibs( vOrigRibs, nSrfBase, nSrfExt, LayerParams.dOffs, LayerParams.dStrand, nRibsPathGrp, LayerParams.vtSlicing)
-- preparo il gruppo con i contorni delle superfici di offset ( necessario per CalcToolPath)
local nLoopGrp = EgtGroup( nRibsPathGrp)
local nSrfId = EgtGetFirstNameInGroup( nRibsPathGrp, TOT_SHELL_TRIM_SURF)
while nSrfId do
local nChunksNbr = EgtSurfFrChunkCount( nSrfId)
for i = 0, nChunksNbr - 1 do
local nRes, nCnt = EgtExtractSurfFrChunkLoops( nSrfId, i, nLoopGrp)
for j = nRes, nRes + nCnt - 1 do
EgtSetName( j, TRIM_SURF_LOOP)
end
end
nSrfId = EgtGetNextName( nSrfId, TOT_SHELL_TRIM_SURF)
end
-- gestisco eventuali intersezioni fra costolature
local bInters, bSpecialCase = HandleRibsIntersections( nRibsGrp, LayerParams, nOffsGrp, nRibsPathGrp, nLoopGrp, bAllTwoStrands, vTypeSequence, tSurfOffs)
EgtSetInfo( nRibsPathGrp or GDB_ID.NULL, KEY_RIBS_INTERS, bInters)
EgtSetInfo( nRibsPathGrp or GDB_ID.NULL, KEY_RIBS_SPECIAL_CASE, bSpecialCase)
-- trim dei setti con le regioni offsettate secondo opportuno overlap
local vRibs = EgtGetNameInGroup( nRibsPathGrp, RIBS_CRV ..'*') or {}
for i = 1, #vRibs do
local nCrvId = vRibs[i]
-- trim con superficie opportuna
local nOverlap = EgtGetInfo( nCrvId, KEY_RIBS_OVERLAP, 'i')
local nType = EgtGetInfo( nCrvId, KEY_RIBS_TYPE, 'i')
if not tSurfOffs[nType][nOverlap] then
-- la costolatura non è fattibile
EgtOutLog( 'Warning: Rib not possibile (layer '.. EgtNumToString( s_nCurrIdx) ..') - CalcPaths')
EgtErase( vRibs[i])
else
local nCrv, nCnt
if tSurfOffs[nType][nOverlap] == GDB_ID.NULL then
-- caso unbounded o esterno in assenza di solido
nCrv = nCrvId
nCnt = 1
else
nCrv, nCnt = EgtTrimCurveWithRegion( nCrvId, tSurfOffs[nType][nOverlap], EgtIf( nType == RIB_TYPE.INTERNAL or nType == RIB_TYPE.SUPPORT, true, false), false)
end
for nInd = 0, nCnt - 1 do
-- verifico vicolo sulla lunghezza
local dLen = EgtCurveLength( nCrv + nInd)
if dLen < MIN_RIBS_LEN then
EgtErase( nCrv + nInd)
else
-- salvo info della superficie di trim associata
EgtSetInfo( nCrv + nInd, KEY_ASSOCIATED_SURF, tSurfOffs[nType][nOverlap])
-- setti chiusi
if EgtCurveIsClosed( nCrv + nInd) then
EgtSetInfo( nCrv + nInd, KEY_CLOSED_CRV, 1)
-- ripristino orientamento originale
local bInvertInfo = EgtGetInfo( nCrv + nInd, KEY_RIBS_INVERT_DIR, 'b') or false
local bInverted = EgtGetInfo( nCrv + nInd, KEY_INVERTED_CRV, 'b') or false
if bInvertInfo ~= bInverted then
EgtInvertCurve( nCrv + nInd)
UpdateInvertInfo( nCrv + nInd)
end
ModifyStartPoint( nCrv + nInd, vPtStart)
EgtSetInfo( nCrv + nInd, KEY_RIBS_LINK, 0)
end
-- se dopo trim ho avuto split in più tratti, salvo alcune info
if nCnt > 1 then
local nStartRib = EgtGetInfo( nCrv + nInd, KEY_START_RIB, 'i')
EgtSetInfo( nStartRib, KEY_SPLIT_AFTER_TRIM, 1)
EgtSetInfo( nCrv + nInd, KEY_SPLIT_AFTER_TRIM, 1)
EgtSetInfo( nCrv + nInd, KEY_SPLIT_AFTER_TRIM_ORDER, nInd)
EgtSetInfo( nCrv + nInd, KEY_SPLIT_AFTER_TRIM_TOT, nCnt)
end
end
end
end
end
-- riordino le costolature
if bSpecialCase then
-- gestione caso speciale di intersezione e 2 passate
ReorderRibsInters2Shells( nRibsPathGrp, LayerParams.dStrand, LayerParams.bRibsInvertOrder)
else
ReorderRibs( nRibsPathGrp, LayerParams.bRibsInvertOrder, LayerParams.dStrand)
end
if not EgtGetFirstNameInGroup( nRibsPathGrp, RIBS_CRV .. '*') then
EgtErase( nRibsPathGrp)
end
-- sistemo le quote delle superfici e dei loop per CalcToolPath
local vLoopIds = EgtGetAllInGroup( nLoopGrp) or {}
for i = 1, #vLoopIds do
EgtMove( vLoopIds[i], LayerParams.dLayHeight * LayerParams.vtSlicing, GDB_RT.GLOB)
end
local vSrfIds = EgtGetNameInGroup( nRibsPathGrp, TOT_SHELL_TRIM_SURF) or {}
for i = 1, #vSrfIds do
EgtMove( vSrfIds[i], LayerParams.dLayHeight * LayerParams.vtSlicing, GDB_RT.GLOB)
end
nCrvGrp = EgtGetNextName( nCrvGrp, CONTOUR_GRP .. '*')
end
end
--------------------------------------------------------------------
----------------- REGIONI CON DIVERSE PASSATE ----------------------
--------------------------------------------------------------------
local function CreateShellNbrSurfaces( nGrp, nShellsNbr)
if not nGrp then return end
local tDiffCrvs = {}
local nMaxShellNbrDiff = 0
local nCrvId = EgtGetFirstNameInGroup( nGrp, SHELL_NBR_CRV .. '*')
while nCrvId do
if EgtCurveIsClosed( nCrvId) then
-- verifico se area significativa
local _, _, dArea = EgtCurveArea( nCrvId)
if dArea and dArea > GEO.EPS_SMALL 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
else
EgtOutLog( 'Warning: ReducedShellNumber is too small (layer '.. EgtNumToString( s_nCurrIdx) ..') - CalcPaths')
end
else
EgtOutLog( 'Error: ReducedShellNumber is not closed (layer '.. EgtNumToString( s_nCurrIdx) ..') - CalcPaths')
table.insert( s_vErr, 'layer ' .. EgtNumToString( s_nCurrIdx) .. ' : ReducedShellNumber is not closed')
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
for i = 1, #vCrvIds do
local nSrfTmp = EgtSurfFlatRegion( nSrfGrp, vCrvIds[i])
local bOk = false
if nSrfTmp then
if not nSrfId then
-- se è la prima curva è quella che definisce la superficie
nSrfId = nSrfTmp
bOk = true
else
bOk = EgtSurfFrAdd( nSrfId, nSrfTmp)
EgtErase( nSrfTmp)
end
end
if not bOk then
EgtOutLog( 'Error: ReducedShellNumber is not considered (layer '.. EgtNumToString( s_nCurrIdx) ..') - CalcPaths')
table.insert( s_vErr, 'layer ' .. EgtNumToString( s_nCurrIdx) .. ' : ReducedShellNumber is not considered')
end
end
if nSrfId then
EgtSetName( nSrfId, SHELL_NBR_SURF .. EgtNumToString( nDiff))
-- salvo come info gli id delle curve che la definiscono
EgtSetInfo( nSrfId, KEY_ASSOCIATED_CRVS, vCrvIds)
end
end
end
--------------------------------------------------------------------
local function ComputeMaxShellNbrDiff( nSrf, nShellNbrSurfGrp)
local nMaxShellNbrDiff = 0
if nShellNbrSurfGrp then
local nId = 1
local nShellNbrSrf = EgtGetFirstNameInGroup( nShellNbrSurfGrp, SHELL_NBR_SURF .. tostring( nId))
while nShellNbrSrf do
-- se interessa la regione considerata aggiorno il nMaxShellNbrDiff
if not EgtSurfFrTestExternal( nSrf, nShellNbrSrf) then
nMaxShellNbrDiff = nId
end
-- passo al successivo
nId = nId + 1
nShellNbrSrf = EgtGetFirstNameInGroup( nShellNbrSurfGrp, SHELL_NBR_SURF .. tostring( nId))
end
end
return nMaxShellNbrDiff
end
----------------------------------------------------------------
local function FindExtraShellRetractionParams( ptP, vIds, LayerParams)
local dCoasting, dWipe, dWipeDir
-- cerco la curva sulla quale si ferma
for i = 1, #vIds do
local dPar = EgtCurveParamAtPoint( vIds[i], ptP, 10 * GEO.EPS_SMALL)
if dPar then
dCoasting = EgtGetInfo( vIds[i], KEY_SHELL_NBR_COASTING, 'd')
dWipe = EgtGetInfo( vIds[i], KEY_SHELL_NBR_WIPE, 'd')
dWipeDir = EgtGetInfo( vIds[i], KEY_SHELL_NBR_WIPE_DIR, 'd')
break
end
end
if not dCoasting then
-- se non ho trovato una curva considero i parametri generali
return LayerParams.dShellNbrCoasting, LayerParams.dShellNbrWipe, LayerParams.dShellNbrWipeDir
else
return dCoasting, dWipe, dWipeDir
end
end
-----------------------------------------------------------------
local function TrimOuterCurveForExtraShellCalc( nOuterCrv, nSrfDiff, nGrpId, vPtStart, LayerParams)
local nCopy = EgtCopyGlob( nOuterCrv, nGrpId)
ModifyStartPoint( nCopy, vPtStart)
-- recupero tutte le curve delle ShellNumber coinvolte
local vShellNbrCrvs = EgtGetInfo( nSrfDiff, KEY_ASSOCIATED_CRVS, 'vi')
-- trim della curva
local nCrv, nCnt = EgtTrimCurveWithRegion( nCopy, nSrfDiff, false, false)
if nCrv and nCnt ~= 0 then
-- verifico se prima e ultima curva possono essere unite
if nCnt > 1 and AreSamePointApprox( EgtEP( nCrv + nCnt - 1), EgtSP( nCrv)) then
EgtRelocateGlob( nCrv + nCnt - 1, nCrv, GDB_IN.AFTER)
EgtAddCurveCompoCurve( nCrv + nCnt - 1, nCrv)
EgtChangeId( nCrv + nCnt - 1, nCrv)
nCnt = nCnt - 1
end
-- assegno le info in base alla curva che li delimita
for nId = nCrv, nCrv + nCnt - 1 do
local ptS = EgtSP( nId)
local dCoastingS, dWipeS, dWipeDirS = FindExtraShellRetractionParams( ptS, vShellNbrCrvs, LayerParams)
local ptE = EgtEP( nId)
local dCoastingE, dWipeE, dWipeDirE = FindExtraShellRetractionParams( ptE, vShellNbrCrvs, LayerParams)
EgtSetInfo( nId, KEY_EXTRA_SHELL_COASTING, {dCoastingS, dCoastingE})
EgtSetInfo( nId, KEY_EXTRA_SHELL_WIPE, {dWipeS, dWipeE})
EgtSetInfo( nId, KEY_EXTRA_SHELL_WIPE_DIR, {dWipeDirS, dWipeDirE})
end
return nCrv, nCnt
else
return nOuterCrv, 0
end
end
--------------------------------------------------------------------
local function UpdateTotalShellSurf( nSrf, nCrv, dStrand, nGrpId)
local nSrfExtraShell = EgtSurfFrFatCurve( nGrpId, nCrv, dStrand - s_dOffsCorr, false)
if nSrfExtraShell then
local vtSrfN = EgtSurfFrNormVersor( nSrf, GDB_ID.ROOT)
local vtSrfExShN = EgtSurfFrNormVersor( nSrfExtraShell, GDB_ID.ROOT)
if vtSrfExShN * vtSrfN < 0 then
EgtInvertSurf( nSrfExtraShell)
end
EgtSurfFrSubtract( nSrf, nSrfExtraShell)
EgtErase( nSrfExtraShell)
end
end
---------------------------------------------------------------------
local function ReorderExtraShells( nPathGrp, dStrand, vPtStart, bPrintInvert)
-- verifico se posso unire due tratti consecutivi della stessa shell
local nFirst = EgtGetFirstNameInGroup( nPathGrp, EXTRA_SHELL_CRV .. '*')
while nFirst do
-- recupero tratti appartenenti alla stessa shell
local sName = EgtGetName( nFirst)
local vShells = EgtGetNameInGroup( nPathGrp, sName)
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
-- verifico se le curve si possono chiudere
vShells = EgtGetNameInGroup( nPathGrp, sName)
for i = 1, #vShells do
if not EgtCurveIsClosed( vShells[i]) then
if dist( EgtSP( vShells[i]), EgtEP( vShells[i])) < dStrand + GEO.EPS_SMALL then
EgtCloseCurveCompo( vShells[i])
end
end
end
nFirst = EgtGetNextName( nCurr, EXTRA_SHELL_CRV .. '*')
end
local vIds = EgtGetNameInGroup( nPathGrp, EXTRA_SHELL_CRV .. '*')
if not vIds then return end
-- eventuale inversione di tutte le curve
if bPrintInvert then
for i = 1, #vIds do
EgtInvertCurve( vIds[i])
UpdateInvertInfo( vIds[i])
end
end
-- cerco di creare percorsi
local k = 0 -- indice da utilizzare per i nomi
while #vIds > 0 do
k = k + 1
-- prendo la prima tra le curve a disposizione
nCurrCrv = vIds[1]
table.remove( vIds, 1)
EgtSetName( nCurrCrv, EXTRA_SHELL_CRV .. tostring(k))
local ptSCurr = EgtSP( nCurrCrv)
local ptECurr = EgtEP( nCurrCrv)
local nCnt = 0
-- se curva è chiusa
if EgtCurveIsClosed( nCurrCrv) then
ModifyStartPoint( nCurrCrv, vPtStart)
-- setto a nil per ripartire subito con curva successiva
nCurrCrv = nil
end
-- scorro alla ricerca di una curva che posso collegare alla corrente
while nCurrCrv do
local bFound = false
for j = 1, #vIds do
if not EgtCurveIsClosed( vIds[j]) then
local ptS = EgtSP( vIds[j])
local ptE = EgtEP( vIds[j])
local bLink = dist( ptS, ptECurr) < 1.5 * dStrand
if dist( ptE, ptECurr) < 1.5 * dStrand then
-- congiungo end-end
EgtInvertCurve( vIds[j])
EgtSetInfo( vIds[j], KEY_INVERTED_CRV, EgtIf( bPrintInvert, 0, 1))
bLink = true
elseif nCnt == 0 and dist( ptS, ptSCurr) < 1.5 * dStrand then
-- congiungo start-start
EgtInvertCurve( nCurrCrv)
EgtSetInfo( nCurrCrv, KEY_INVERTED_CRV, EgtIf( bPrintInvert, 0, 1))
bLink = true
end
if bLink then
nCnt = nCnt + 1
EgtRelocateGlob( vIds[j], nCurrCrv, GDB_IN.AFTER)
EgtSetName( vIds[j], EXTRA_SHELL_CRV .. tostring( k))
-- aggiorno per collegamento successivo
bFound = true
nCurrCrv = vIds[j]
ptSCurr = EgtSP( vIds[j])
ptECurr = EgtEP( vIds[j])
table.remove( vIds, j)
break
end
end
end
-- se non ho più curve da collegare
if not bFound then
nCurrCrv = nil
end
end
end
end
--------------------------------------------------------------------
local function CalcExtraShellsPath( nMaxShellNbrDiff, nShellNbrGrp, nCrvGrpId, dOffs, LayerParams, 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( s_nCurrIdx)..') - CalcPaths')
return
end
for nInd = nMaxShellNbrDiff, 1, -1 do
dOffs = dOffs + LayerParams.dStrand * ( 1 - EgtIf( nInd == LayerParams.nShellsNbr, 0, LayerParams.nStrandOverlap / 100))
local nSrfDiff = EgtGetFirstNameInGroup( nShellNbrGrp, SHELL_NBR_SURF .. tostring( nInd))
local nOuterCrv = EgtGetFirstNameInGroup( nCrvGrpId, OUTER_CRV)
while nOuterCrv do
-- trim della curva con la superficie
local nTrimCrv, nTrimCnt = TrimOuterCurveForExtraShellCalc( nOuterCrv, nSrfDiff, nGrpId, vPtStart, LayerParams)
for nCrvT = nTrimCrv, nTrimCrv + nTrimCnt - 1 do
-- calcolo offset della curva ( è il percorso della shell)
EgtModifyCurveExtrusion( nCrvT, LayerParams.vtSlicing, GDB_RT.GLOB)
local nOffs, nOffsCnt = EgtOffsetCurveAdv( nCrvT, - dOffs)
EgtErase( nCrvT)
for nCrvOffs = nOffs, nOffs + nOffsCnt - 1 do
-- trim con la regione già occupata dal altre shell
local nCrv, nCnt = EgtTrimCurveWithRegion( nCrvOffs, nSrfTrim, true, true)
if nCrv and nCnt ~= 0 then
for nId = nCrv, nCrv + nCnt - 1 do
local dLen = EgtCurveLength( nId)
local bValid = true
if EgtCurveIsClosed( nId) then
bValid = VerifyPath( nId, LayerParams.dStrand, LayerParams.vtSlicing, nGrpId)
end
-- verifico se soddisfa vincolo sulla lunghezza
if dLen > MIN_LEN and bValid then
EgtSetStatus( nId, GDB_ST.ON)
EgtModifyCurveExtrusion( nId, LayerParams.vtSlicing, GDB_RT.GLOB)
EgtSetName( nId, EXTRA_SHELL_CRV .. tostring( nMaxShellNbrDiff - nInd + 1))
if nInd == LayerParams.nShellsNbr then
EgtSetInfo( nId, KEY_TYPE, TYPE.EXTRA_OUTER_SHELL)
else
EgtSetInfo( nId, KEY_TYPE, TYPE.EXTRA_SHELL)
end
-- aggiorno la superficie occupata dalle shell con quella appena calcolata (tenendo conto dell'overlap)
UpdateTotalShellSurf( nSrfTrim, nId, ( 1 - LayerParams.nStrandOverlap / 100) * LayerParams.dStrand, nGrpId)
-- se la superficie si annulla non è possibile realizzare altro, quindi cancello tutte le curve rimaste
if EgtSurfFrChunkCount( nSrfTrim) == 0 then
for j = nId + 1, nCrv + nCnt - 1 do
EgtErase( j)
end
for j = nCrvT + 1, nTrimCrv + nTrimCnt - 1 do
EgtErase( j)
end
-- aggiorno superficie
EgtSurfFrOffset( nSrfTrim, - LayerParams.nStrandOverlap / 100 * LayerParams.dStrand)
-- riordino le curve appena create e se possibile creo percorsi chiusi
ReorderExtraShells( nGrpId, LayerParams.dStrand, vPtStart, LayerParams.bPrintInvert)
return
end
else
EgtErase( nId)
end
end
end
end
end
nOuterCrv = EgtGetNextName( nOuterCrv, OUTER_CRV)
end
end
-- aggiorno superificie
EgtSurfFrOffset( nSrfTrim, - LayerParams.nStrandOverlap / 100 * LayerParams.dStrand)
-- riordino le curve appena create e se possibile creo percorsi chiusi
ReorderExtraShells( nGrpId, LayerParams.dStrand, vPtStart, LayerParams.bPrintInvert)
end
--------------------------------------------------------------------
------------------ AUX SOLIDS -------------------------------------
--------------------------------------------------------------------
local function ComputeTrimSurfWithOverlapsForAuxSolids( vIds, nSrfBase, dStrand, nGrp, vtSlicing)
-- per ogni valore di overlap creo le superfici con cui fare i trim
local vSurfOffs = {}
for i = 1, #vIds do
local nOverlap = EgtGetInfo( vIds[i][1], KEY_AUX_SOLIDS_OVERLAP, 'i')
if not vSurfOffs[nOverlap] then
local dNewOffs = nOverlap / 100 * dStrand
local bOk, bExists, nSrfOffs = ComputeSurfOffset( nSrfBase, nGrp, dNewOffs, vtSlicing)
if bOk then
vSurfOffs[nOverlap] = nSrfOffs
else
EgtOutLog( 'Warning: AuxSolid without correct overlap (layer '.. EgtNumToString( s_nCurrIdx) ..') - CalcPaths')
vSurfOffs[nOverlap] = nSrfBase
end
end
end
return vSurfOffs
end
-----------------------------------------------------------------------
local function UpdateTrimSurfWithAuxSolidsOffset( nSrfSolid, nSrfBase, dStrand, nCrvGrp, vtSlicing)
-- offset della superifice del solido
local bOk, bExists, nSrfOffs = ComputeSurfOffset( nSrfSolid, nCrvGrp, dStrand, vtSlicing)
if not bOk then
EgtOutLog( 'Error : creation of AuxSolid region for TotTrimSurfRegion failed (layer '.. EgtNumToString( s_nCurrIdx) ..') - CalcPaths')
table.insert( s_vErr, 'layer ' .. EgtNumToString( s_nCurrIdx) .. ' : error in computing region for internal elements')
elseif nSrfOffs then
if not EgtSurfFrSubtract( nSrfBase, nSrfOffs) then
EgtOutLog( 'Error : EgtSurfFrSubtract with AuxSolid for TotTrimSurfRegion failed (layer '.. EgtNumToString( s_nCurrIdx) ..') - CalcPaths')
table.insert( s_vErr, 'layer ' .. EgtNumToString( s_nCurrIdx) .. ' : error in computing region for internal elements')
end
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 not nSrfZigZag then
-- uso la superficie occupata dall'aux solid, anche se potrebbe non corrispondere perfettamente con quella effettiva del percorso a zigzag
EgtOutLog( 'Warning : approximation of the region filled by AuxSolid (layer '.. EgtNumToString( s_nCurrIdx) ..') - CalcPaths')
nSrfZigZag = nSrf
end
-- aggiorno la TotShellSurfForTrim
if not EgtSurfFrSubtract( nSrfBase, nSrfZigZag) then
EgtOutLog( 'Error : EgtSurfFrSubtract with AuxSolid for TotTrimSurfRegion failed (layer '.. EgtNumToString( s_nCurrIdx) ..') - CalcPaths')
table.insert( s_vErr, 'layer ' .. EgtNumToString( s_nCurrIdx) .. ' : error in computing region for internal elements')
end
end
EgtErase( nGrpTmp)
end
-------------------------------------------------------------------
local function AddExtraZigZag( nSrf, sName, dStrand, vtSlicing, nGrp, nSrfTrim)
local vIds = EgtGetNameInGroup( nGrp, sName)
if not vIds then return end
local vtDir = EgtSV( vIds[1], GDB_ID.ROOT)
local vtYLoc = vtSlicing ^ vtDir
local nOuterLoop, nCnt = EgtExtractSurfFrChunkLoops( nSrf, 0, nGrp)
for i = 1, #vIds do
local _, dParE = EgtCurveDomain( vIds[i])
local ptS = EgtUP( vIds[i], dParE - 1, GDB_ID.ROOT) + dStrand * vtYLoc
local ptE = EgtEP( vIds[i], GDB_ID.ROOT) + dStrand * vtYLoc
local nExtraCrv = EgtLine( nGrp, ptS, ptE, GDB_RT.GLOB)
-- verifico se la linea aggiuntiva serve
local dDist = EgtPointCurveDist( EgtMP( nExtraCrv), nOuterLoop)
if dDist < 0.5 * dStrand - 100 * GEO.EPS_SMALL then
-- verifico se si trova nella regione ammissibile
if EgtCurveWithRegionClassify( nExtraCrv, nSrfTrim) == GDB_CRC.IN then
EgtInvertCurve( nExtraCrv)
EgtAddCurveCompoLine( vIds[i], ptE, GDB_RT.GLOB)
EgtAddCurveCompoCurve( vIds[i], nExtraCrv)
end
end
EgtErase( nExtraCrv)
end
for nId = nOuterLoop, nOuterLoop + nCnt - 1 do
EgtErase( nId)
end
end
-------------------------------------------------------------------
local function ComputeAuxSolidsGenericInfill( nSrf, dStrand, vtSlicing, sName, nPathGrp, vPtStart, nOrigSurf, nOverlap, nAuxSolidsGrp)
-- estraggo i contorni della superficie ( perimetro)
GetPathsFromSurf( nSrf, sName, TYPE.AUX_SOLID, nPathGrp, vPtStart)
-- preparo la superficie con cui fare trim degli infill
local dOffs = dStrand * ( nOverlap / 100 - 0.5)
local bOk, bExists, nSrfTrim = ComputeSurfOffset( nSrf, nPathGrp, dOffs, vtSlicing)
if not bOk then
EgtOutLog( 'Warning: AuxSolid Infill without correct overlap (layer '.. EgtNumToString( s_nCurrIdx) ..') - CalcPaths')
nSrfTrim = EgtCopyGlob( nSrf, nPathGrp)
elseif not bExists then
EgtOutLog( 'Warning: AuxSolid Infill not possibile (layer '.. EgtNumToString( s_nCurrIdx) ..') - CalcPaths')
return
end
-- recupero gli infill associati
local sNameInfill = AUX_SOLIDS_INFILL_CRV .. tostring( nOrigSurf)
local vInfillIds = EgtGetNameInGroup( nAuxSolidsGrp, sNameInfill .. '*') or {}
-- eseguo trim con la superficie
for i = 1, #vInfillIds do
local nCrv = EgtCopyGlob( vInfillIds[i], nPathGrp)
local nRes, nCnt = EgtTrimCurveWithRegion( nCrv, nSrfTrim, true, true)
for nId = nRes, nRes + nCnt - 1 do
-- verifico se lunghezza minima
local dLen = EgtCurveLength( nId)
if dLen < MIN_INFILL_LEN then
EgtErase( nId)
else
EgtSetName( nId, sName)
EgtSetInfo( nId, KEY_TYPE, TYPE.INFILL)
EgtSetInfo( nId, KEY_ASSOCIATED_SURF, nSrfTrim)
EgtModifyCurveExtrusion( nId, vtSlicing)
end
end
end
end
--------------------------------------------------------------------
local function CalcAuxSolidsPaths( nSliceGrp, nSolidGrp, LayerParams, vPtStart)
-- recupero i solidi ausiliari dividendoli per nome
local vSolidIds = {}
local nFirst = EgtGetFirstNameInGroup( nSolidGrp, AUX_SOLIDS_CRV .. '*')
while nFirst do
local sName = EgtGetName( nFirst)
local vIds = EgtGetNameInGroup( nSolidGrp, sName)
table.insert( vSolidIds, vIds)
nFirst = EgtGetNextName( vIds[#vIds], AUX_SOLIDS_CRV .. '*')
end
-- 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 '.. EgtNumToString( s_nCurrIdx) ..') - CalcPaths')
else
local vSurfOffs = ComputeTrimSurfWithOverlapsForAuxSolids( vSolidIds, nSrfBase, LayerParams.dStrand, nSolidPathGrp, LayerParams.vtSlicing)
for i = 1, #vSolidIds do
-- creo la flat region corrispondente al solido ausiliario
local sName = EgtGetName( vSolidIds[i][1])
local nOverlap = EgtGetInfo( vSolidIds[i][1], KEY_AUX_SOLIDS_OVERLAP, 'i')
local nOrigSurf = EgtGetInfo( vSolidIds[i][1], KEY_ORIGINAL_SURF, 'i')
local nSrfId = EgtSurfFlatRegion( nSolidPathGrp, vSolidIds[i])
if nSrfId then
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][1], KEY_AUX_SOLIDS_INFILL, 'i')
if nInfillType == FILL_TYPE.NONE then
-- estraggo i contorni della superficie ( serve solo perimetro)
GetPathsFromSurf( nFirst + j, sNewName, TYPE.AUX_SOLID, nSolidPathGrp, vPtStart)
-- aggiorno la trim surf
UpdateTrimSurfWithAuxSolidsOffset( nFirst + j, nSrfBase, LayerParams.dStrand, nSolidPathGrp, LayerParams.vtSlicing)
elseif nInfillType == FILL_TYPE.OFFSET then
ComputeOffsetSolidFill( nFirst + j, LayerParams.dStrand, LayerParams.vtSlicing, sNewName, TYPE.AUX_SOLID, nSolidPathGrp, vPtStart)
-- aggiorno la trim surf
UpdateTrimSurfWithAuxSolidsOffset( nFirst + j, nSrfBase, LayerParams.dStrand, nSolidPathGrp, LayerParams.vtSlicing)
elseif nInfillType == FILL_TYPE.ZIGZAG then
ComputeZigZagSolidFill( nFirst + j, LayerParams.dStrand, LayerParams.vtSlicing, sNewName, TYPE.AUX_SOLID, nSolidPathGrp, vSurfOffs[nOverlap])
-- 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)
else
ComputeAuxSolidsGenericInfill( nFirst + j, LayerParams.dStrand, LayerParams.vtSlicing, sNewName, nSolidPathGrp, vPtStart, nOrigSurf, nOverlap, nSolidGrp)
-- aggiorno la trim surf
UpdateTrimSurfWithAuxSolidsOffset( nFirst + j, nSrfBase, LayerParams.dStrand, nSolidPathGrp, LayerParams.vtSlicing)
end
end
else
EgtOutLog( 'Error : creation of AuxSolid region failed (layer '.. EgtNumToString( s_nCurrIdx) ..') - CalcPaths')
table.insert( s_vErr, 'layer ' .. EgtNumToString( s_nCurrIdx) .. ' : creation of AuxSolid region failed')
end
end
end
-- verifico se il gruppo contine qualcosa
if not EgtGetFirstNameInGroup( nSolidPathGrp, AUX_SOLIDS_CRV .. '*') then
EgtErase( nSolidPathGrp)
end
-- passo al gruppo di contorni successivo
nCrvGrp = EgtGetNextName( nCrvGrp, CONTOUR_GRP .. '*')
end
end
---------------------------------------------------------------------
function CalcPaths.Exec( nPartId)
s_nPartId = nPartId
local vLayIds = EgtGetNameInGroup( s_nPartId, SLICE_LAYER.."*")
if not vLayIds then
EgtOutBox( 'Error no slice', 'PathCalc')
return true
end
-- recupero i parametri per calcolo dei path
local LayerParams = GetLayerParamsForPathCalc()
local nFirstSolidLay = EgtGetInfo( s_nPartId, KEY_FIRST_SOLID_LAY, 'i') or -1
local nLastSolidLay = EgtGetInfo( s_nPartId, KEY_LAST_SOLID_LAY, 'i') or -1
-- scorro tutti i suoi layer
for nIdx = 1, #vLayIds do
s_nCurrIdx = nIdx
local nRibsGrp = EgtGetFirstNameInGroup( vLayIds[nIdx], RIBS_GRP)
local nAuxSolidsGrp = EgtGetFirstNameInGroup( vLayIds[nIdx], AUX_SOLIDS_GRP)
local nInfillGrp = EgtGetFirstNameInGroup( vLayIds[nIdx], INFILL_GRP)
-- regioni con diverso numero di passate
local nShellNbrGrp = EgtGetFirstNameInGroup( vLayIds[nIdx], SHELL_NBR_GRP)
local nMaxShell = max( LayerParams.nShellsNbr, LayerParams.nFloorNbr, LayerParams.nCeilNbr)
CreateShellNbrSurfaces( nShellNbrGrp, nMaxShell)
local nShellNbrSurfGrp = EgtGetFirstGroupInGroup( nShellNbrGrp or GDB_ID.NULL)
-- recupero gli start point per il layer
local vPtStart = GetLayerStartPoint( vLayIds[nIdx], LayerParams.vtSlicing)
-- scorro tutti i gruppi di contorni
local nCrvGrpId = EgtGetFirstNameInGroup( vLayIds[nIdx], CONTOUR_GRP.."*") or GDB_ID.NULL
while nCrvGrpId ~= GDB_ID.NULL do
-- verifico se il path è già stato calcolato
local nGrpId = EgtGetFirstNameInGroup( nCrvGrpId, PATH_GRP) or GDB_ID.NULL
if nGrpId == GDB_ID.NULL then
nGrpId = EgtGroup( nCrvGrpId)
EgtSetName( nGrpId, PATH_GRP)
else
EgtEmptyGroup( nGrpId)
EgtSetStatus( nGrpId, GDB_ST.ON)
end
-- recupero la superficie ottenuta dallo slicing
local nSrf = EgtGetFirstNameInGroup( nCrvGrpId, LAYER_SRF)
if nSrf then
local nMaxShellNbrDiff = ComputeMaxShellNbrDiff( nSrf, nShellNbrSurfGrp)
nMaxShellNbrDiff = min( nMaxShellNbrDiff, LayerParams.nShellsNbr)
-- parete esterna
local vOldIds
local bPrevExists = true
local dOffs = - LayerParams.dOffs - 0.5 * LayerParams.dStrand
if nMaxShellNbrDiff < LayerParams.nShellsNbr then
dOffs = dOffs + LayerParams.dStrand
local bOk, bExists, nSrfId = ComputeSurfOffset( nSrf, nCrvGrpId, - dOffs, LayerParams.vtSlicing)
if not bOk then
EgtOutLog( 'Error : ExtOffset failed (layer '.. EgtNumToString( nIdx) ..') - CalcPaths')
table.insert( s_vErr, 'layer ' .. EgtNumToString( nIdx) .. ' : creation of OuterShell failed')
elseif not bExists then
EgtOutLog( 'Warning : ExtOffset not possible (layer '.. EgtNumToString( nIdx) ..') - CalcPaths')
else
-- se offset riuscito, estraggo i contorni (pareti esterne)
vOldIds = GetPathsFromSurf( nSrfId, SHELL_CRV ..'0', TYPE.OUTER_SHELL, nGrpId, vPtStart)
end
bPrevExists = bExists
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, LayerParams.vtSlicing)
if not bOk then
EgtOutLog( 'Error : IntOffset failed (layer '.. EgtNumToString( nIdx) ..') - CalcPaths')
table.insert( s_vErr, 'layer ' .. EgtNumToString( nIdx) .. ' : creation of InnerShell failed')
elseif not bExists then
EgtOutLog( 'Warning : IntOffset ' .. EgtNumToString( nInd) .. ' not possible (layer '.. EgtNumToString( nIdx) ..') - CalcPaths')
else
-- se offset riuscito, estraggo i contorni ( pareti interne)
local vNewIds = GetPathsFromSurf( nSrfId, SHELL_CRV..tostring( nInd), TYPE.INNER_SHELL, nGrpId, vPtInnerStart)
ReorderPath( vOldIds, vNewIds)
vOldIds = vNewIds
-- se questo offset esiste ma il precedente no, allora il precedente è un errore da segnalare
if not bPrevExists then
local sElement = EgtIf( nInd > 1, 'IntOffset ' .. EgtNumToString( nInd - 1), 'ExtOffset')
EgtOutLog( 'Error :' .. sElement .. ' failed (layer '.. EgtNumToString( nIdx) ..') - CalcPaths')
table.insert( s_vErr, 'layer ' .. EgtNumToString( nIdx) .. ' : creation of ' .. EgtIf( nInd > 1, 'InnerShell', 'OuterShell') .. ' failed')
end
end
bPrevExists = bExists
EgtErase( nSrfId)
end
-- preparo superficie occupata dalle shell da usare per trim
local dSurfTrimOffs = dOffs + LayerParams.dStrand
if nMaxShellNbrDiff > 0 then
-- se hai extra shell tieni conto anche dell'overlap ammesso
dSurfTrimOffs = dOffs + ( 1 - LayerParams.nStrandOverlap / 100) * LayerParams.dStrand - s_dOffsCorr
end
local bOkTrim, bExistsTrim, nSrfTrim = ComputeSurfOffset( nSrf, nCrvGrpId, - dSurfTrimOffs, LayerParams.vtSlicing)
if not bOkTrim then
EgtOutLog( 'Error : IntOffset for TotTrimSurfRegion failed (layer '.. EgtNumToString( nIdx) ..') - CalcPaths')
table.insert( s_vErr, 'layer ' .. EgtNumToString( nIdx) .. ' : error in computing region for internal elements')
elseif bExistsTrim then
EgtSetName( nSrfTrim, TOT_SHELL_TRIM_SURF)
EgtSetStatus( nSrfTrim, GDB_ST.OFF)
-- se questo offset esiste ma il precedente no, allora il precedente è un errore da segnalare
if not bPrevExists then
EgtOutLog( 'Error : IntOffset' .. EgtNumToString( LayerParams.nShellsNbr - 1 - nMaxShellNbrDiff) .. ' failed (layer '.. EgtNumToString( nIdx) ..') - CalcPaths')
table.insert( s_vErr, 'layer ' .. EgtNumToString( nIdx) .. ' : creation of InnerShell failed')
end
end
-- eventuali pareti interne coinvolte dal diverso numero di passate
if nMaxShellNbrDiff > 0 then
CalcExtraShellsPath( nMaxShellNbrDiff, nShellNbrSurfGrp, nCrvGrpId, dOffs, LayerParams, vPtInnerStart)
end
end
-- passo al gruppo di contorni successivo
nCrvGrpId = EgtGetNextName( nCrvGrpId, CONTOUR_GRP.."*") or GDB_ID.NULL
end
-- gestione solidi ausiliari ( se no floor o ceil)
if nAuxSolidsGrp and ( nFirstSolidLay + LayerParams.nFloorNbr <= nIdx and nIdx <= nLastSolidLay - LayerParams.nCeilNbr or LayerParams.nShellsNbr == 0) then
CalcAuxSolidsPaths( vLayIds[nIdx], nAuxSolidsGrp, LayerParams, vPtStart)
end
-- gestione riempimenti
if LayerParams.nShellsNbr > 0 then
-- infill
if nFirstSolidLay + LayerParams.nFloorNbr <= nIdx and nIdx <= nLastSolidLay - LayerParams.nCeilNbr then
CalcInfillPaths( vLayIds[nIdx], nInfillGrp, LayerParams)
-- floor
elseif nFirstSolidLay <= nIdx and nIdx < nFirstSolidLay + LayerParams.nFloorNbr then
CalcSolidFillPath( vLayIds[nIdx], LayerParams, vPtStart, LayerParams.nFloorType)
-- ceil
elseif nLastSolidLay - LayerParams.nCeilNbr < nIdx and nIdx <= nLastSolidLay then
CalcSolidFillPath( vLayIds[nIdx], LayerParams, vPtStart, LayerParams.nCeilType)
end
end
-- gestione costolature
if nRibsGrp then
CalcRibsPaths( vLayIds[nIdx], nRibsGrp, LayerParams, vPtStart)
end
if EgtProcessEvents( EgtIf( PRINT, 200, 0) + nIdx / #vLayIds * 100, 0) == 1 then
EgtDraw()
return false
end
end
if #s_vErr > 0 then
EgtOutBox( 'CalcPath Error on :\n' .. table.concat( s_vErr, '\n'), 'Calculating Paths')
end
return true
end
---------------------------------------------------------------------
return CalcPaths