-- FaceData.lua by Egalware s.r.l. 2024/04/18 -- Libreria lettura o calcolo dati e proprietà delle facce di una trimesh -- 2024/04/02 PRIMA VERSIONE CALCOLO LAVORAZIONI CON STRATEGIE -- Tabella per definizione modulo local FaceData = {} -- carico librerie local BeamLib = require( 'BeamLib') local Logs = require( 'Logs') --------------------------------------------------------------------- -- restituisce la matrice delle adiacenze di Proc dove i e j sono le facce e a(ij) è l'angolo tra di esse; 0 se nessuna adiacenza function FaceData.GetAdjacencyMatrix( Proc) local vAdj = {} -- essendo la matrice simmetrica a diagonale nulla, ne calcolo solo la metà superiore for i = 1, Proc.nFct do vAdj[i] = {} for j = i + 1, Proc.nFct do _, _, _, vAdj[i][j] = EgtSurfTmFacetsContact( Proc.id, i - 1, j - 1, GDB_ID.ROOT) if not vAdj[i][j] then vAdj[i][j] = 0 end end end -- riempio di conseguenza il resto della matrice for i = 1, Proc.nFct do vAdj[i][i] = 0 for j = i + 1, Proc.nFct do vAdj[j][i] = vAdj[i][j] end end return vAdj end --------------------------------------------------------------------- -- restituisce un vettore con gli indici (0 based) delle facce triangolari (o quasi) di Proc function FaceData.GetTriangularFaces( Proc) -- se la feature ha una sola faccia, esco subito if Proc.nFct <= 1 then return end local vTriangularFaces = {} for i = 1, Proc.nFct do if BeamLib.Is3EdgesApprox( Proc, i - 1) then table.insert( vTriangularFaces, i - 1) end end return vTriangularFaces end ------------------------------------------------------------------------------------------------------------- local function GetNotAdjacentFaces( Proc, idFace) local NotAdjacentFaces = {} for i = 1, Proc.nFct do if Proc.Faces[i].id ~= idFace then local bIsAdjacent = false for j = 1, #Proc.Faces[idFace + 1].Adjacencies do if Proc.Faces[i].id == Proc.Faces[idFace + 1].Adjacencies[j] then bIsAdjacent = true end end if not bIsAdjacent then table.insert( NotAdjacentFaces, Proc.Faces[i]) end end end return NotAdjacentFaces end --------------------------------------------------------------------- -- restituisce una tabella che correla numero di adiacenze e id delle facce con quello stesso numero di adiacenze function FaceData.GetFacesByAdjacencyNumber( Proc) -- se la feature ha una sola faccia, esco subito if Proc.nFct <= 1 then return {} end local FacesByAdjacencyNumber = {} for i = 1, 10 do FacesByAdjacencyNumber[i] = {} end for i = 1, Proc.nFct do if #Proc.Faces[i].Adjacencies > 0 then table.insert( FacesByAdjacencyNumber[#Proc.Faces[i].Adjacencies], Proc.Faces[i]) end end return FacesByAdjacencyNumber end ------------------------------------------------------------------------------------------------------------- function FaceData.GetEdgesInfo( ProcOrId, idFace ) local Edges = {} -- disambiguazione feature vs id trimesh local Proc = {} if type( ProcOrId) == "table" then Proc = ProcOrId elseif type( ProcOrId) == "number" then Proc.id = ProcOrId else error( 'GetEdgesInfo : Only feature or trimesh supported') end local nFaceType, EdgesEgt = EgtSurfTmGetFacetOutlineInfo( Proc.id, idFace, GDB_ID.ROOT) for i = 1, #EdgesEgt do local nPreviousEdgeIndex = i - 1 if i == 1 then nPreviousEdgeIndex = #EdgesEgt end local nNextEdgeIndex = i + 1 if i == #EdgesEgt then nNextEdgeIndex = 1 end -- l'elevazione si tiene sempre positiva e la normale sempre diretta verso l'interno della faccia -- per sapere se il lato è aperto c'è la proprietà apposita bIsOpen local CurrentEdge = {} CurrentEdge.idAdjacentFace = EdgesEgt[i].Adj CurrentEdge.dLength = EdgesEgt[i].Len CurrentEdge.dElevation = abs( EdgesEgt[i].Elev) CurrentEdge.bIsOpen = EdgesEgt[i].Open CurrentEdge.vtN = Vector3d( EdgesEgt[i].Norm) if CurrentEdge.bIsOpen then CurrentEdge.vtN = -CurrentEdge.vtN end CurrentEdge.bIsStartOpen = EdgesEgt[nPreviousEdgeIndex].Open CurrentEdge.bIsEndOpen = EdgesEgt[nNextEdgeIndex].Open CurrentEdge.ptStart = Point3d( EdgesEgt[i].Start) CurrentEdge.ptEnd = Point3d( EdgesEgt[nNextEdgeIndex].Start) CurrentEdge.vtEdge = CurrentEdge.ptEnd - CurrentEdge.ptStart ; CurrentEdge.vtEdge:normalize() CurrentEdge.sType = 'Standard' CurrentEdge.id = i - 1 -- se nella Proc ci sono le adiacenze e il lato ha adiacenza, si salva l'angolo con la faccia adiacente if Proc.AdjacencyMatrix then if CurrentEdge.idAdjacentFace > -1 then CurrentEdge.dAdjacencyAngle = Proc.AdjacencyMatrix[idFace + 1][CurrentEdge.idAdjacentFace + 1] end end table.insert( Edges, CurrentEdge) end return nFaceType, Edges end ------------------------------------------------------------------------------------------------------------- function FaceData.GetFacesInfo( Proc, Part, FacesToGet) local Faces = {} local function FaceIsToGet( nIndex) if not FacesToGet then return false end for i = 1, #FacesToGet do -- correggo indice perche' id delle facce è 0-based if FacesToGet[i] == nIndex - 1 then return true end end return false end local vAdj if Proc.AdjacencyMatrix then vAdj = Proc.AdjacencyMatrix else vAdj = FaceData.GetAdjacencyMatrix( Proc) end if not Proc.nFct then Proc.nFct = EgtSurfTmFacetCount( Proc.id) or 0 end for i = 1, Proc.nFct do Faces[i] = {} Faces[i].id = i - 1 Faces[i].idTrimesh = Proc.id Faces[i].ptCenter, Faces[i].vtN = EgtSurfTmFacetCenter( Proc.id, i - 1, GDB_ID.ROOT) if Proc.nFct < 7 or FaceIsToGet( i) then -- frame OCS faccia Faces[i].frFrameHV = Frame3d( Faces[i].ptCenter, Faces[i].vtN) -- elevazione calcolata rispetto al box della parte Faces[i].dElevation = EgtSurfTmFacetElevationInBBox( Proc.id, i - 1, Part.b3Part, true, GDB_ID.ROOT) -- TODO qui sarebbe meglio l'area vera e non quella del rettangolo minimo local _, dLongDimension, dShortDimension = EgtSurfTmFacetMinAreaRectangle( Proc.id, i - 1, GDB_ID.ROOT) Faces[i].dArea = dShortDimension * dLongDimension Faces[i].dLMinRectangle = dLongDimension Faces[i].dWMinRectangle = dShortDimension -- volume approssimato di materiale asportato lavorando questa faccia Faces[i].dMachinedVolumeApprox = Faces[i].dArea * Faces[i].dElevation local nFaceType, Edges = FaceData.GetEdgesInfo( Proc, i - 1) Faces[i].bIsOkForMachining = nFaceType < 1 Faces[i].Edges = Edges -- adiacenze della faccia -- TODO chiamarle in modo che si capisca che sono solo gli id e non l'intero oggetto faccia Faces[i].Adjacencies = {} for j = 1, Proc.nFct do if vAdj[i][j] and vAdj[i][j] ~= 0 and ( i ~= j) then table.insert( Faces[i].Adjacencies, j - 1) end end end end return Faces end ------------------------------------------------------------------------------------------------------------- function FaceData.IsFaceRectangle( Face) -- recupero gruppo per geometrie temporanee local idTempGroup = BeamLib.GetTempGroup() local nContourId, nContourCnt = EgtExtractSurfTmFacetLoops( Face.idTrimesh, Face.id, idTempGroup) if nContourCnt > 1 then error( 'IsFaceRectangle : too many loops') end local bIsRectangular = EgtCurveIsARectangle( nContourId) return bIsRectangular end ------------------------------------------------------------------------------------------------------------- function FaceData.IsFaceParallelogram( Face) -- recupero gruppo per geometrie temporanee local idTempGroup = BeamLib.GetTempGroup() local nContourId, nContourCnt = EgtExtractSurfTmFacetLoops( Face.idTrimesh, Face.id, idTempGroup) if nContourCnt > 1 then error( 'IsFaceParallelogram : too many loops') end local bIsTrapezoid = EgtCurveIsATrapezoid( nContourId) local bIsRhomboid = false -- un parallelogramma è un trapezoide con i lati paralleli a due a due if bIsTrapezoid and AreOppositeVectorApprox( Face.Edges[1].vtN, Face.Edges[3].vtN) and AreOppositeVectorApprox( Face.Edges[2].vtN, Face.Edges[4].vtN) then bIsRhomboid = true end return bIsRhomboid end ------------------------------------------------------------------------------------------------------------- local function CompareBottomFaces( FaceA, FaceB) local dMaxVolumeRelativeChange = 0.15 -- si prende la faccia con volume lavorato maggiore if FaceA.dMachinedVolumeApprox > ( 1 + dMaxVolumeRelativeChange) * FaceB.dMachinedVolumeApprox + 10 * GEO.EPS_SMALL then return true elseif FaceB.dMachinedVolumeApprox > ( 1 + dMaxVolumeRelativeChange) * FaceA.dMachinedVolumeApprox + 10 * GEO.EPS_SMALL then return false -- se volume lavorato simile, si prende la faccia con minore elevazione else if FaceA.dElevation < FaceB.dElevation - 10 * GEO.EPS_SMALL then return true elseif FaceB.dElevation < FaceA.dElevation - 10 * GEO.EPS_SMALL then return false else return false end end end ------------------------------------------------------------------------------------------------------------- local function CompareEdgesBottomFace( EdgeA, EdgeB) -- prima i lati con facce adiacenti if ( EdgeA.idAdjacentFace > -1) and ( EdgeB.idAdjacentFace < 0) then return true elseif ( EdgeA.idAdjacentFace < 0) and ( EdgeB.idAdjacentFace > -1) then return false -- se entrambi con facce adiacenti, si sceglie quello convesso (non chiuso) else if EdgeA.bIsOpen and not ( EdgeB.bIsOpen) then return true elseif not ( EdgeA.bIsOpen) and EdgeB.bIsOpen then return false -- se entrambi aperti o entrambi chiusi, si sceglie quello più lungo else if EdgeA.dLength > EdgeB.dLength then return true elseif EdgeA.dLength < EdgeB.dLength then return false end end end end ------------------------------------------------------------------------------------------------------------- -- TODO valutare refactoring per mettere i calcoli del tunnel in una funzione -- TODO creare le facce tunnel solo se non ci sono già. Verirficare all'inizio se già presente in AddGrpId e nel caso riferire all'id di quella esistente e ricalcolare solo le informazioni della faccia. -- TODO test iniziale replicato in GetMainFaces local function GetTunnelFaces( Proc, Part) local TunnelAddedFaces = {} if not ( ( Proc.Topology.bIsThrough and Proc.Topology.bAllRightAngles and Proc.nFct < 5) or ( Proc.nFct == 1 ) or Proc.Topology.sName == 'Bevel-2-Blind') then error( 'GetTunnelFaces : Topology not implemented') end -- direzione del tunnel local vtTunnelDirection = V_NULL() if Proc.nFct == 1 then local EdgesSortedByElevation = BeamLib.TableCopyDeep( Proc.Faces[1].Edges) table.sort( EdgesSortedByElevation, function (a, b) return a.dElevation > b.dElevation end ) vtTunnelDirection = Proc.Faces[1].vtN ^ EdgesSortedByElevation[1].vtN else vtTunnelDirection = Proc.Faces[1].vtN ^ Proc.Faces[ Proc.Faces[1].Adjacencies[1] + 1].vtN end -- centro del tunnel local frTunnel = Frame3d( Proc.Faces[1].ptCenter, vtTunnelDirection) local b3Tunnel = EgtGetBBoxRef( Proc.id, GDB_BB.STANDARD, frTunnel) local ptTunnelCenter = b3Tunnel:getCenter() ptTunnelCenter:toGlob( frTunnel) -- recupero gruppo per geometria addizionale local nAddGrpId = BeamLib.GetAddGroup( Proc.idPart) if not nAddGrpId then -- TODO gestire meglio questo errore. Non conviene creare e verificare all'inizio se il gruppo esiste? EgtOutLog( 'Error : missing AddGroup') return TunnelAddedFaces end -- faccia centrale local nMiddleTmId = EgtSurfTmPlaneInBBox( nAddGrpId, ptTunnelCenter, vtTunnelDirection, Part.b3Part, GDB_ID.ROOT) -- TODO se non si riesce a costruire la faccia bisogna dare errore o semplicemente non ritornarla?? for i = 1, Proc.nFct do EgtCutSurfTmPlane( nMiddleTmId, Proc.Faces[i].ptCenter, -Proc.Faces[i].vtN, false, GDB_ID.ROOT) end -- facce laterali local nLateralTmId = EgtCopyGlob( Proc.id, nAddGrpId) or GDB_ID.NULL EgtCutSurfTmPlane( nLateralTmId, ptTunnelCenter, -vtTunnelDirection, false, GDB_ID.ROOT) -- unione facce -- TODO cambiare nome alla trimesh?? non contiene più solamente la faccia di mezzo TunnelAddedFaces.MiddleFaceTm = {} TunnelAddedFaces.MiddleFaceTm.id = EgtSurfTmBySewing( nAddGrpId, { nMiddleTmId, nLateralTmId}, true) -- TODO c'è un modo più elegante per raccogliere le informazioni delle facce aggiunte TunnelAddedFaces.MiddleFaceTm.sType = 'Tunnel' TunnelAddedFaces.MiddleFaceTm.nFct = EgtSurfTmFacetCount( TunnelAddedFaces.MiddleFaceTm.id) TunnelAddedFaces.MiddleFaceTm.Faces = FaceData.GetFacesInfo( TunnelAddedFaces.MiddleFaceTm, Part) return TunnelAddedFaces end ------------------------------------------------------------------------------------------------------------- local function GetBottomFaces( Proc) local BottomFaces = {} if Proc.Topology.sFamily == 'Tunnel' then return nil elseif not ( Proc.Topology.sFamily == 'Rabbet' or Proc.Topology.sFamily == 'VGroove' or Proc.Topology.sFamily == 'Groove' or Proc.Topology.sFamily == 'Pocket' or Proc.Topology.sFamily == 'Bevel' or Proc.Topology.sFamily == 'DoubleBevel' or Proc.Topology.sFamily == 'Cut' or Proc.Topology.sFamily == 'HeadCut' or Proc.Topology.sFamily == 'TailCut') then error( 'GetBottomFace : Topology not implemented') end if Proc.nFct == 1 then return { Proc.Faces[1]} end -- la faccia di fondo ha sempre Fct - 1 adiacenze, tranne caso speciale DoubleBevel con facce di chiusura triangolari local FacesByAdjacencyNumber = FaceData.GetFacesByAdjacencyNumber( Proc) if FacesByAdjacencyNumber then BottomFaces = FacesByAdjacencyNumber[ Proc.nFct - 1] -- caso speciale DoubleBevel if #BottomFaces == 0 then if Proc.nParts == 1 then BottomFaces = FacesByAdjacencyNumber[ Proc.nFct / 2] -- DoubleBevel composto da più parti else for i = #FacesByAdjacencyNumber, 1, -1 do if #FacesByAdjacencyNumber[i] > 0 then BottomFaces = FacesByAdjacencyNumber[i] break end end -- se non sono state trovate facce di fondo significa che nessuna faccia ha adiacenze -> DoubleBevel-2 if #BottomFaces == 0 then BottomFaces = Proc.Faces end end end -- si rimuovono le facce non adatte ad essere lavorate local nBottomFaces = #BottomFaces local nCurrentFace = 1 while nCurrentFace <= nBottomFaces do if not BottomFaces[nCurrentFace].bIsOkForMachining then table.remove( BottomFaces, nCurrentFace) nBottomFaces = nBottomFaces - 1 end nCurrentFace = nCurrentFace + 1 end -- la BottomFace 1 è quella che permette di asportare il volume maggiore; nei casi ambigui si sceglie quella a minor elevazione table.sort( BottomFaces, CompareBottomFaces) end if #BottomFaces == 0 then return nil end BottomFaces[1].sType = 'Bottom' -- calcolo MainEdges implementato solo se 4 lati esatti if #BottomFaces[1].Edges ~= 4 then return BottomFaces end BottomFaces[1].MainEdges = {} BottomFaces[1].MainEdges.LongEdges = {} BottomFaces[1].MainEdges.SideEdges = {} local EdgesSorted = {} for i = 1, #BottomFaces[1].Edges do table.insert( EdgesSorted, {}) EdgesSorted[#EdgesSorted].nIndex = i EdgesSorted[#EdgesSorted].dLength = BottomFaces[1].Edges[i].dLength EdgesSorted[#EdgesSorted].idAdjacentFace = BottomFaces[1].Edges[i].idAdjacentFace end table.sort( EdgesSorted, CompareEdgesBottomFace) local nFirstLongEdgeIndex if #EdgesSorted > 0 then nFirstLongEdgeIndex = EdgesSorted[1].nIndex end for i = 1, #BottomFaces[1].Edges do local nPreviousEdgeIndex = i - 1 if i == 1 then nPreviousEdgeIndex = #BottomFaces[1].Edges end local nNextEdgeIndex = i + 1 if i == #BottomFaces[1].Edges then nNextEdgeIndex = 1 end local CurrentEdge = {} CurrentEdge.idAdjacentFace = BottomFaces[1].Edges[i].idAdjacentFace CurrentEdge.vtN = BottomFaces[1].Edges[i].vtN CurrentEdge.dLength = BottomFaces[1].Edges[i].dLength CurrentEdge.bIsOpen = BottomFaces[1].Edges[i].bIsOpen CurrentEdge.dElevation = BottomFaces[1].Edges[i].dElevation CurrentEdge.bIsStartOpen = BottomFaces[1].Edges[i].bIsStartOpen CurrentEdge.bIsEndOpen = BottomFaces[1].Edges[i].bIsEndOpen CurrentEdge.ptStart = BottomFaces[1].Edges[i].ptStart CurrentEdge.ptEnd = BottomFaces[1].Edges[i].ptEnd CurrentEdge.vtEdge = BottomFaces[1].Edges[i].vtEdge CurrentEdge.id = BottomFaces[1].Edges[i].id if nFirstLongEdgeIndex then if i == nFirstLongEdgeIndex then BottomFaces[1].MainEdges.LongEdges[1] = CurrentEdge BottomFaces[1].MainEdges.LongEdges[1].sType = 'Long' elseif nNextEdgeIndex == nFirstLongEdgeIndex then BottomFaces[1].MainEdges.SideEdges[1] = CurrentEdge BottomFaces[1].MainEdges.SideEdges[1].sType = 'Side' elseif nPreviousEdgeIndex == nFirstLongEdgeIndex then BottomFaces[1].MainEdges.SideEdges[2] = CurrentEdge BottomFaces[1].MainEdges.SideEdges[2].sType = 'Side' else BottomFaces[1].MainEdges.LongEdges[2] = CurrentEdge BottomFaces[1].MainEdges.LongEdges[2].sType = 'Long' end end end return BottomFaces end ------------------------------------------------------------------------------------------------------------- local function GetLongFaces( Proc, MainFaces) local LongFaces = {} if Proc.nFct > 6 then error( 'GetLongFaces : Topology not implemented') elseif Proc.nFct == 1 then return {} end local BottomFace local BottomFaces = MainFaces.BottomFaces or GetBottomFaces( Proc) if BottomFaces and #BottomFaces > 0 then BottomFace = BottomFaces[1] end local idFirstLongFace = GDB_ID.NULL local idSecondLongFace = GDB_ID.NULL if not BottomFace then local FacesSortedByGreatestArea = {} for i = 1, Proc.nFct do FacesSortedByGreatestArea[i] = {} FacesSortedByGreatestArea[i].id = Proc.Faces[i].id FacesSortedByGreatestArea[i].dArea = Proc.Faces[i].dArea end table.sort( FacesSortedByGreatestArea, function (a, b) return a.dArea > b.dArea end) idFirstLongFace = FacesSortedByGreatestArea[1].id local FacesNotAdjacent = GetNotAdjacentFaces( Proc, idFirstLongFace) idSecondLongFace = FacesNotAdjacent[1].id elseif BottomFace.MainEdges then if BottomFace.MainEdges.LongEdges[1].idAdjacentFace > -1 then idFirstLongFace = BottomFace.MainEdges.LongEdges[1].idAdjacentFace end if BottomFace.MainEdges.LongEdges[2].idAdjacentFace > -1 then idSecondLongFace = BottomFace.MainEdges.LongEdges[2].idAdjacentFace end end if idFirstLongFace > -1 and Proc.Faces[idFirstLongFace + 1].bIsOkForMachining then table.insert( LongFaces, Proc.Faces[idFirstLongFace + 1]) end if idSecondLongFace > -1 and Proc.Faces[idSecondLongFace + 1].bIsOkForMachining then table.insert( LongFaces, Proc.Faces[idSecondLongFace + 1]) end for i = 1, #LongFaces do LongFaces[i].sType = 'Long' -- calcolo MainEdges possibile solo se 4 lati esatti if #LongFaces[i].Edges ~= 4 then break end LongFaces[i].MainEdges = {} LongFaces[i].MainEdges.SideEdges = {} LongFaces[i].MainEdges.OppositeEdges = {} for j = 1, #LongFaces[i].Edges do local nPreviousEdgeIndex = j - 1 if j == 1 then nPreviousEdgeIndex = #LongFaces[1].Edges end local nNextEdgeIndex = j + 1 if j == #LongFaces[i].Edges then nNextEdgeIndex = 1 end local CurrentEdge = {} CurrentEdge.idAdjacentFace = LongFaces[i].Edges[j].idAdjacentFace CurrentEdge.vtN = LongFaces[i].Edges[j].vtN CurrentEdge.dLength = LongFaces[i].Edges[j].dLength CurrentEdge.bIsOpen = LongFaces[i].Edges[j].bIsOpen CurrentEdge.dElevation = LongFaces[i].Edges[j].dElevation CurrentEdge.bIsStartOpen = LongFaces[i].Edges[j].bIsStartOpen CurrentEdge.bIsEndOpen = LongFaces[i].Edges[j].bIsEndOpen CurrentEdge.ptStart = LongFaces[i].Edges[j].ptStart CurrentEdge.ptEnd = LongFaces[i].Edges[j].ptEnd CurrentEdge.vtEdge = LongFaces[i].Edges[j].vtEdge CurrentEdge.id = LongFaces[i].Edges[j].id if Proc.Topology.sFamily == 'Tunnel' then if CurrentEdge.idAdjacentFace > -1 then table.insert( LongFaces[i].MainEdges.SideEdges, CurrentEdge) LongFaces[i].MainEdges.SideEdges[#LongFaces[i].MainEdges.SideEdges].sType = 'Side' else table.insert( LongFaces[i].MainEdges.OppositeEdges, CurrentEdge) LongFaces[i].MainEdges.OppositeEdges[#LongFaces[i].MainEdges.OppositeEdges].sType = 'Opposite' end else if CurrentEdge.idAdjacentFace == BottomFace.id then LongFaces[i].MainEdges.BottomEdge = CurrentEdge LongFaces[i].MainEdges.BottomEdge.sType = 'Bottom' elseif LongFaces[i].Edges[nNextEdgeIndex].idAdjacentFace == BottomFace.id then LongFaces[i].MainEdges.SideEdges[1] = CurrentEdge LongFaces[i].MainEdges.SideEdges[1].sType = 'Side' elseif LongFaces[i].Edges[nPreviousEdgeIndex].idAdjacentFace == BottomFace.id then LongFaces[i].MainEdges.SideEdges[2] = CurrentEdge LongFaces[i].MainEdges.SideEdges[2].sType = 'Side' else table.insert( LongFaces[i].MainEdges.OppositeEdges, CurrentEdge) LongFaces[i].MainEdges.OppositeEdges[#LongFaces[i].MainEdges.OppositeEdges].sType = 'Opposite' end end end end return LongFaces end ------------------------------------------------------------------------------------------------------------- local function GetSideFaces( Proc, MainFaces) local SideFaces = {} if Proc.nFct > 6 then error( 'GetSideFaces : Topology not implemented') elseif Proc.nFct == 1 then return {} end local BottomFace local BottomFaces = MainFaces.BottomFaces or GetBottomFaces( Proc) if BottomFaces and #BottomFaces > 0 then BottomFace = BottomFaces[1] end local LongFaces = MainFaces.LongFaces or GetLongFaces( Proc, MainFaces) local idFirstSideFace = GDB_ID.NULL local idSecondSideFace = GDB_ID.NULL if LongFaces[1] and LongFaces[1].MainEdges then if not LongFaces[1].MainEdges.SideEdges[1].bIsOpen then idFirstSideFace = LongFaces[1].MainEdges.SideEdges[1].idAdjacentFace end if not LongFaces[1].MainEdges.SideEdges[2].bIsOpen then idSecondSideFace = LongFaces[1].MainEdges.SideEdges[2].idAdjacentFace end end if idFirstSideFace > -1 and Proc.Faces[idFirstSideFace + 1].bIsOkForMachining then table.insert( SideFaces, Proc.Faces[idFirstSideFace + 1]) SideFaces[#SideFaces].sType = 'Side' end if idSecondSideFace > -1 and Proc.Faces[idSecondSideFace + 1].bIsOkForMachining then table.insert( SideFaces, Proc.Faces[idSecondSideFace + 1]) SideFaces[#SideFaces].sType = 'Side' end for i = 1, #SideFaces do SideFaces[i].sType = 'Side' -- calcolo MainEdges possibile solo se 4 lati esatti if #SideFaces[i].Edges ~= 4 then break end SideFaces[i].MainEdges = {} SideFaces[i].MainEdges.LongEdges = {} SideFaces[i].MainEdges.OppositeEdges = {} for j = 1, #SideFaces[i].Edges do local nPreviousEdgeIndex = j - 1 if j == 1 then nPreviousEdgeIndex = #SideFaces[1].Edges end local nNextEdgeIndex = j + 1 if j == #SideFaces[i].Edges then nNextEdgeIndex = 1 end local CurrentEdge = {} CurrentEdge.idAdjacentFace = SideFaces[i].Edges[j].idAdjacentFace CurrentEdge.vtN = SideFaces[i].Edges[j].vtN CurrentEdge.dLength = SideFaces[i].Edges[j].dLength CurrentEdge.bIsOpen = SideFaces[i].Edges[j].bIsOpen CurrentEdge.dElevation = SideFaces[i].Edges[j].dElevation CurrentEdge.bIsStartOpen = SideFaces[i].Edges[j].bIsStartOpen CurrentEdge.bIsEndOpen = SideFaces[i].Edges[j].bIsEndOpen CurrentEdge.ptStart = SideFaces[i].Edges[j].ptStart CurrentEdge.ptEnd = SideFaces[i].Edges[j].ptEnd CurrentEdge.vtEdge = SideFaces[i].Edges[j].vtEdge CurrentEdge.id = SideFaces[i].Edges[j].id if Proc.Topology.sFamily == 'Tunnel' then if CurrentEdge.idAdjacentFace > -1 then table.insert( SideFaces[i].MainEdges.LongEdges, CurrentEdge) else table.insert( SideFaces[i].MainEdges.OppositeEdges, CurrentEdge) end else if CurrentEdge.idAdjacentFace == BottomFace.id then SideFaces[i].MainEdges.BottomEdge = CurrentEdge SideFaces[i].MainEdges.BottomEdge.sType = 'Bottom' elseif SideFaces[i].Edges[nNextEdgeIndex].idAdjacentFace == BottomFace.id then SideFaces[i].MainEdges.LongEdges[1] = CurrentEdge SideFaces[i].MainEdges.LongEdges[1].sType = 'Long' elseif SideFaces[i].Edges[nPreviousEdgeIndex].idAdjacentFace == BottomFace.id then SideFaces[i].MainEdges.LongEdges[2] = CurrentEdge SideFaces[i].MainEdges.LongEdges[2].sType = 'Long' else table.insert( SideFaces[i].MainEdges.OppositeEdges, CurrentEdge) SideFaces[i].MainEdges.OppositeEdges[#SideFaces[i].MainEdges.OppositeEdges].sType = 'Opposite' end end end end return SideFaces end ------------------------------------------------------------------------------------------------------------- -- recupero facce principali della feature, in base alla topologia -- TODO test iniziale replicato in GetTunnelFaces function FaceData.GetMainFaces( Proc, Part) local MainFaces = {} -- CASO 1 : Feature tipo LapJoint if Proc.Topology.sFamily == 'Rabbet' or Proc.Topology.sFamily == 'VGroove' or Proc.Topology.sFamily == 'Groove' or Proc.Topology.sFamily == 'Pocket' or Proc.Topology.sFamily == 'Tunnel' or Proc.Topology.sFamily == 'Bevel' or Proc.Topology.sFamily == 'DoubleBevel' or Proc.Topology.sFamily == 'Cut' or Proc.Topology.sFamily == 'HeadCut' or Proc.Topology.sFamily == 'TailCut' then if Proc.nParts == 1 and ( ( Proc.Topology.bIsThrough and Proc.Topology.bAllRightAngles and Proc.nFct < 5) or ( Proc.nFct == 1) or Proc.Topology.sName == 'Bevel-2-Blind') then MainFaces.TunnelAddedFaces = GetTunnelFaces( Proc, Part) end MainFaces.BottomFaces = GetBottomFaces( Proc) if Proc.nParts == 1 then MainFaces.LongFaces = GetLongFaces( Proc, MainFaces) MainFaces.SideFaces = GetSideFaces( Proc, MainFaces) -- caso tipo DoubleBevel con facce separate else MainFaces.LongFaces = {} MainFaces.SideFaces = {} end else MainFaces = nil end return MainFaces end ------------------------------------------------------------------------------------------------------------- return FaceData