Imports EgtUILib

Friend Module CamAuto

   Private m_MainWindow As MainWindow = DirectCast(Application.Current.MainWindow, MainWindow)

   Friend Function AddMachinings(nPartId As Integer) As Boolean
      Dim nWarn As Integer = 0
      Return AddMachinings(nPartId, nWarn)
   End Function

   Friend Function AddMachinings(nPartId As Integer, ByRef nWarn As Integer) As Boolean
      Dim bDripOk As Boolean = VerifyVacuumsForDrip(nPartId)
      If Not bDripOk Then nWarn = 1
      EgtLuaCreateGlobTable("CAM")
      SetLuaStandardCamParams(bDripOk)
      EgtLuaSetGlobIntVar("CAM.PARTID", nPartId)
      Dim nErr As Integer = 999
      Dim bOk As Boolean = EgtLuaExecFile(m_MainWindow.GetCamAutoDir() & "\CamAuto.lua")
      bOk = bOk AndAlso EgtLuaGetGlobIntVar("CAM.ERR", nErr) AndAlso nErr = 0
      bOk = bOk AndAlso EgtLuaCallFunction("CAM.Add")
      EgtLuaGetGlobIntVar("CAM.ERR", nErr)
      EgtLuaResetGlobVar("CAM")
      If nErr <> 0 Then
         bOk = False
         EgtOutLog("Error in CamAuto : " & nErr.ToString())
      End If
      m_MainWindow.m_CurrentProjectPageUC.ResetOrderMachiningFlag()
      Return bOk
   End Function

   Friend Function AddWaterJetMachining( nOperId As Integer, ByRef nWarn As Integer) As Boolean
      EgtLuaCreateGlobTable("CAM")
      SetLuaStandardCamParams()
      EgtLuaSetGlobIntVar("CAM.OPERID", nOperId)
      Dim nErr As Integer = 999
      Dim bOk As Boolean = EgtLuaExecFile(m_MainWindow.GetCamAutoDir() & "\CamAuto.lua")
      bOk = bOk AndAlso EgtLuaGetGlobIntVar("CAM.ERR", nErr) AndAlso nErr = 0
      bOk = bOk AndAlso EgtLuaCallFunction("CAM.AddWaterJet")
      EgtLuaGetGlobIntVar("CAM.ERR", nErr)
      EgtLuaResetGlobVar("CAM")
      If nErr <> 0 Then
         bOk = False
         EgtOutLog("Error in CamAuto : " & nErr.ToString())
      End If
      Return bOk
   End Function

   Friend Function EraseMachinings(nPartId As Integer) As Boolean
      EgtLuaCreateGlobTable("CAM")
      EgtLuaSetGlobIntVar("CAM.PARTID", nPartId)
      Dim nErr As Integer = 999
      Dim bOk As Boolean = EgtLuaExecFile(m_MainWindow.GetCamAutoDir() & "\CamAuto.lua")
      bOk = bOk AndAlso EgtLuaGetGlobIntVar("CAM.ERR", nErr) AndAlso nErr = 0
      bOk = bOk AndAlso EgtLuaCallFunction("CAM.Erase")
      EgtLuaGetGlobIntVar("CAM.ERR", nErr)
      EgtLuaResetGlobVar("CAM")
      If nErr <> 0 Then
         bOk = False
         EgtOutLog("Error in CamAuto : " & nErr.ToString())
      End If
      m_MainWindow.m_CurrentProjectPageUC.ResetOrderMachiningFlag()
      m_MainWindow.m_CurrentProjectPageUC.ResetProjectNcRestart()
      Return bOk
   End Function

   Friend Function InvertVerticalCut(nOperId As Integer) As Boolean
      EgtLuaCreateGlobTable("CAM")
      EgtLuaSetGlobIntVar("CAM.OPERID", nOperId)
      Dim nErr As Integer = 999
      Dim bOk As Boolean = EgtLuaExecFile(m_MainWindow.GetCamAutoDir() & "\CamAuto.lua")
      bOk = bOk AndAlso EgtLuaGetGlobIntVar("CAM.ERR", nErr) AndAlso nErr = 0
      bOk = bOk AndAlso EgtLuaCallFunction("CAM.InvertVerticalCut")
      EgtLuaGetGlobIntVar("CAM.ERR", nErr)
      EgtLuaResetGlobVar("CAM")
      If nErr <> 0 Then
         bOk = False
         EgtOutLog("Error in CamAuto : " & nErr.ToString())
      End If
      Return bOk
   End Function

   Friend Function ResetAllMachinings() As Boolean
      Dim nWarn As Integer = 0
      Return ResetAllMachinings(nWarn)
   End Function

   Friend Function ResetAllMachinings(ByRef nWarn As Integer) As Boolean
      ' Cancello tutte le lavorazioni
      EraseMachinings(GDB_ID.NULL)
      ' Se progetto con pezzi piani
      Dim nPrjType As Integer = m_MainWindow.m_CurrentProjectPageUC.GetCurrentProjectType()
      If nPrjType = CurrentProjectPageUC.PRJ_TYPE.FLATS Then
         ' Reinserisco tutte le lavorazioni piane
         AddMachinings(GDB_ID.NULL, nWarn)
      ' Se altrimenti progetto con cornici
      ElseIf nPrjType = CurrentProjectPageUC.PRJ_TYPE.FRAMES Then
         ' Reinserisco tutte le lavorazioni delle cornici
         AddFrameMachinings(m_MainWindow.m_FrameCutPageUC.m_FrameMachiningUC.m_dStartTrim, m_MainWindow.m_FrameCutPageUC.m_FrameMachiningUC.m_dEndTrim)
      End If
      Return True
   End Function

   Friend Function RemoveFinalEmptyPhases() As Boolean
      Dim nOpeId As Integer = EgtGetLastOperation()
      While nOpeId <> GDB_ID.NULL
         Dim nPrevOpeId As Integer = EgtGetPrevOperation(nOpeId)
         If EgtGetOperationType(nOpeId) = MCH_OY.DISP AndAlso EgtIsOperationEmpty(nOpeId) Then
            EgtRemoveLastPhase()
         Else
            Exit While
         End If
         nOpeId = nPrevOpeId
      End While
      Return True
   End Function

   Friend Function RemoveLastPhase() As Boolean
      ' Non posso eliminare la prima fase
      Dim nLastPhase As Integer = EgtGetPhaseCount()
      If nLastPhase = 1 Then Return False
      ' Sposto le lavorazioni in coda a quelle della fase precedente
      Dim nDispId As Integer = EgtGetPhaseDisposition(nLastPhase)
      Dim nMachId As Integer = EgtGetNextOperation(nDispId)
      While nMachId <> GDB_ID.NULL
         EgtChangeOperationPhase(nMachId, nLastPhase - 1)
         nMachId = EgtGetNextOperation(nDispId)
      End While
      ' Rimuovo l'ultima fase 
      Return EgtRemoveLastPhase()
   End Function

   Friend Function UpdateAllMachiningsToolpaths() As Boolean
      EgtLuaCreateGlobTable("CAM")
      SetLuaStandardCamParams()
      Dim nErr As Integer = 999
      Dim bOk As Boolean = EgtLuaExecFile(m_MainWindow.GetCamAutoDir() & "\CamAuto.lua")
      bOk = bOk AndAlso EgtLuaGetGlobIntVar("CAM.ERR", nErr) AndAlso nErr = 0
      bOk = bOk AndAlso EgtLuaCallFunction("CAM.UpdateAllTp")
      EgtLuaGetGlobIntVar("CAM.ERR", nErr)
      EgtLuaResetGlobVar("CAM")
      If nErr <> 0 Then
         bOk = False
         EgtOutLog("Error in CamAuto : " & nErr.ToString())
      End If
      Return bOk
   End Function

   Friend Function SortAllMachinings() As Boolean
      EgtLuaCreateGlobTable("CAM")
      SetLuaStandardCamParams()
      Dim nErr As Integer = 999
      Dim bOk As Boolean = EgtLuaExecFile(m_MainWindow.GetCamAutoDir() & "\CamAuto.lua")
      bOk = bOk AndAlso EgtLuaGetGlobIntVar("CAM.ERR", nErr) AndAlso nErr = 0
      bOk = bOk AndAlso EgtLuaCallFunction("CAM.Sort")
      EgtLuaGetGlobIntVar("CAM.ERR", nErr)
      EgtLuaResetGlobVar("CAM")
      If nErr <> 0 Then
         bOk = False
         EgtOutLog("Error in CamAuto : " & nErr.ToString())
      End If
      Return bOk
   End Function

   Friend Function SpecialApplyDisposition(nDispId As Integer, bRecalc As Boolean, Optional ResetOrderMachiningFlag As Boolean = True) As Boolean
      EgtLuaCreateGlobTable("CAM")
      EgtLuaSetGlobIntVar("CAM.DISPID", nDispId)
      EgtLuaSetGlobBoolVar("CAM.RECALC", bRecalc)
      Dim nErr As Integer = 999
      Dim bOk As Boolean = EgtLuaExecFile(m_MainWindow.GetCamAutoDir() & "\CamAuto.lua")
      bOk = bOk AndAlso EgtLuaGetGlobIntVar("CAM.ERR", nErr) AndAlso nErr = 0
      bOk = bOk AndAlso EgtLuaCallFunction("CAM.SpecApplyDisp")
      EgtLuaGetGlobIntVar("CAM.ERR", nErr)
      EgtLuaResetGlobVar("CAM")
      If nErr <> 0 Then
         bOk = False
         EgtOutLog("Error in CamAuto : " & nErr.ToString())
      End If
      If ResetOrderMachiningFlag Then
         m_MainWindow.m_CurrentProjectPageUC.ResetOrderMachiningFlag()
      End If
      Return bOk
   End Function

   Friend Function VerifyVacuumsForDrip(nPartId As Integer) As Boolean
      ' Se un pezzo
      If nPartId <> GDB_ID.NULL Then
         ' Verifico contenga layer per lavorazioni da sotto con entità
         If EgtGetGroupObjs(EgtGetFirstNameInGroup(nPartId, NAME_DRIPCUT)) = 0 And
            EgtGetGroupObjs(EgtGetFirstNameInGroup(nPartId, NAME_UNDERDRILL)) = 0 Then
            Return True
         End If
      ' Se tutti i pezzi
      Else
         ' Salvo fase attualmente corrente
         Dim nOriPhase As Integer = EgtGetCurrPhase()
         ' Ciclo su tutti i pezzi presenti nei grezzi dell'ultima fase di lavorazione
         EgtSetCurrPhase(EgtGetPhaseCount())
         Dim bFound As Boolean = False
         Dim nRawId As Integer = EgtGetFirstRawPart()
         While nRawId <> GDB_ID.NULL
            If EgtVerifyRawPartCurrPhase(nRawId) Then
               Dim nMyPartId As Integer = EgtGetFirstPartInRawPart(nRawId)
               While nMyPartId <> GDB_ID.NULL
                  ' se ci sono lavorazioni da sotto
                  If EgtGetGroupObjs(EgtGetFirstNameInGroup(nMyPartId, NAME_DRIPCUT)) > 0 Or
                     EgtGetGroupObjs(EgtGetFirstNameInGroup(nMyPartId, NAME_UNDERDRILL)) > 0 Then
                     bFound = True
                  End If
                  nMyPartId = EgtGetNextPartInRawPart(nPartId)
               End While
            End If
            nRawId = EgtGetNextRawPart(nRawId)
         End While
         ' Ripristino fase corrente originale
         EgtSetCurrPhase(nOriPhase)
         ' Se non trovate lavorazioni da sotto, esco
         If Not bFound Then Return True
      End If
      ' Verifico che il diametro della lama installata permetta l'utilizzo della ventosa
      Dim dSawDiam As Double
      If EgtTdbSetCurrTool(m_MainWindow.m_CurrentMachine.sCurrSaw) AndAlso
         EgtTdbGetCurrToolParam(MCH_TP.DIAM, dSawDiam) Then
         Return (dSawDiam <= m_MainWindow.m_CurrentMachine.dMaxSawDiamForVac)
      End If
      Return False
   End Function

   Friend Function UpdateVacuumsForDrip() As Boolean
      Dim bOk As Boolean = True
      ' Salvo fase attualmente corrente
      Dim nOriPhase As Integer = EgtGetCurrPhase()
      ' Carico le ventose
      LoadVacuumCups()
      ' Box complessivo dei pezzi con tagli da sotto
      Dim b3Tot As New BBox3d
      ' Ciclo su tutti i pezzi presenti nei grezzi dell'ultima fase di lavorazione
      EgtSetCurrPhase(EgtGetPhaseCount())
      Dim nRawId As Integer = EgtGetFirstRawPart()
      While nRawId <> GDB_ID.NULL
         If EgtVerifyRawPartCurrPhase(nRawId) Then
            Dim nPartId As Integer = EgtGetFirstPartInRawPart(nRawId)
            While nPartId <> GDB_ID.NULL
               ' reset eventuali vecchie informazioni
               RemoveOneMoveInfo(nPartId)
               ' se ci sono lavorazioni da sotto nel pezzo si processa
               If EgtGetGroupObjs(EgtGetFirstNameInGroup(nPartId, NAME_DRIPCUT)) > 0 Or
                  EgtGetGroupObjs(EgtGetFirstNameInGroup(nPartId, NAME_UNDERDRILL)) > 0 Then
                  Dim rmData As New RawMoveData
                  Dim b3Part As New BBox3d
                  If PutVacuumCupsOnPart(nPartId, rmData, b3Part) Then
                     SaveOneMoveInfo(nPartId, rmData)
                     b3Tot.Add(b3Part)
                  Else
                     bOk = False
                     EgtOutLog("Error on UpdateVacuumsForDrip in Part " & nPartId.ToString())
                  End If
               End If
               nPartId = EgtGetNextPartInRawPart(nPartId)
            End While
         End If
         nRawId = EgtGetNextRawPart(nRawId)
      End While
      ' Scarico le ventose
      RemoveVacuumCups()
      ' Salvo box complessivo
      Dim nMarkId As Integer = m_MainWindow.m_CurrentProjectPageUC.AddProjectMark()
      If b3Tot.IsEmpty Then
         Return EgtRemoveInfo(nMarkId, INFO_DRIPBBOX)
      Else
         Return EgtSetInfo(nMarkId, INFO_DRIPBBOX, b3Tot)
      End If
      ' Ripristino fase corrente originale
      EgtSetCurrPhase(nOriPhase)
      Return bOk
   End Function

   Friend Function DeactivateAllMachinings() As Boolean
      Return EgtSetAllOperationsMode(False)
   End Function

   Friend Function ActivateAllMachinings() As Boolean
      Return EgtSetAllOperationsMode(True)
   End Function

   Friend Function HideAllMachinings() As Boolean
      Dim nId As Integer = EgtGetFirstOperation()
      While nId <> GDB_ID.NULL
         If EgtGetOperationType(nId) <> MCH_OY.DISP Then
            EgtSetOperationStatus(nId, False)
         End If
         nId = EgtGetNextOperation(nId)
      End While
      Return True
   End Function

   Friend Function ShowAllCurrPhaseMachinings() As Boolean
      ' Parto dalla prima lavorazione successiva alla disposizione di fase
      Dim nId As Integer = EgtGetPhaseDisposition(EgtGetCurrPhase())
      nId = EgtGetNextOperation(nId)
      ' Finchè c'è una lavorazione
      While nId <> GDB_ID.NULL
         ' Se disposizione sono alla fase successiva
         If EgtGetOperationType(nId) = MCH_OY.DISP Then Exit While
         ' Se abilitata
         If EgtGetOperationMode(nId) Then
            EgtSetOperationStatus(nId, True)
         End If
         ' Passo alla successiva
         nId = EgtGetNextOperation(nId)
      End While
      Return True
   End Function

   Friend Function RemoveFinalHome() As Boolean
      Dim nId As Integer = EgtGetLastActiveOperation()
      Return EgtRemoveOperationHome(nId)
   End Function

   Friend Function VerifySetup(ByRef sMissingTools As String) As Boolean
      Dim bOk As Boolean = True
      Dim bIsMultiCut = (EgtGetHeadId("H101") <> GDB_ID.NULL)
      sMissingTools = String.Empty
      Dim nId As Integer = EgtGetFirstOperation()
      While nId <> GDB_ID.NULL
         If IsValidMachining(nId) Then
            Dim nType As Integer = MCH_OY.NONE
            EgtGetMachiningParam(MCH_MP.TYPE, nType)
            Dim sTuuid As String = String.Empty
            Dim sTool As String = String.Empty
            Dim sTool2 As String = String.Empty
            EgtGetMachiningParam(MCH_MP.TUUID, sTuuid)
            EgtTdbGetToolFromUUID(sTuuid, sTool)
            If String.IsNullOrWhiteSpace( sTool) Then
               Dim sMchTool As String = ""
               EgtGetMachiningParam( MCH_MP.TOOL, sMchTool)
               bOk = False
               If sMissingTools.IndexOf(sMchTool) = -1 Then
                  sMissingTools = sMissingTools & sMchTool & ", "
               End If
            ElseIf nType = MCH_OY.SAWING Or nType = MCH_OY.SAWROUGHING Or nType = MCH_OY.SAWFINISHING Then
               If bIsMultiCut Then
                  ' L'utensile sulla seconda testa ha lo stesso nome di quello sulla prima con suffisso "-2"
                  If sTool.Substring(sTool.Length() - 2) = "-2" Then
                     sTool = sTool.Remove(sTool.Length() - 2)
                  End If
                  sTool2 = sTool & "-2"
               End If
               If String.Compare(sTool, m_MainWindow.m_CurrentMachine.sCurrSaw) <> 0 AndAlso
                  ( String.IsNullOrWhiteSpace( sTool2) OrElse String.Compare(sTool2, m_MainWindow.m_CurrentMachine.sCurrSaw) <> 0) AndAlso
                  String.Compare(sTool, m_MainWindow.m_CurrentMachine.sCurrDripSaw) <> 0 Then
                  bOk = False
                  If sMissingTools.IndexOf(sTool) = -1 Then
                     sMissingTools = sMissingTools & sTool & ", "
                  End If
               End If
            ElseIf nType = MCH_OY.DRILLING Then
               If String.Compare(sTool, m_MainWindow.m_CurrentMachine.sCurrDrill) <> 0 And
                  String.Compare(sTool, m_MainWindow.m_CurrentMachine.sCurrDripDrill) <> 0 And
                  Not FindToolOnChanger(sTool) Then
                  bOk = False
                  If sMissingTools.IndexOf(sTool) = -1 Then
                     sMissingTools = sMissingTools & sTool & ", "
                  End If
               End If
            ElseIf nType = MCH_OY.MILLING Then
               ' Verifico anche le lame perchè il taglio di lama singolo sulle cornici è una lavorazione di fresatura
               If String.Compare(sTool, m_MainWindow.m_CurrentMachine.sCurrMill) <> 0 And
                  Not FindToolOnChanger(sTool) And
                  String.Compare(sTool, m_MainWindow.m_CurrentMachine.sCurrSaw) <> 0 Then
                  bOk = False
                  If sMissingTools.IndexOf(sTool) = -1 Then
                     sMissingTools = sMissingTools & sTool & ", "
                  End If
               End If
            ElseIf nType = MCH_OY.WATERJETTING Then
               If String.Compare(sTool, m_MainWindow.m_CurrentMachine.sCurrWaterJet) <> 0 And
                  Not FindToolOnChanger(sTool) Then
                  bOk = False
                  If sMissingTools.IndexOf(sTool) = -1 Then
                     sMissingTools = sMissingTools & sTool & ", "
                  End If
               End If
            End If
         End If
         nId = EgtGetNextOperation(nId)
      End While
      Return bOk
   End Function

   Private Function FindToolOnChanger(sTool As String) As Boolean
      ' Ricerca nel cambia utensili automatico
      For i As Integer = 0 To m_MainWindow.m_CurrentMachine.ToolChangerNbr() - 1
         If String.Compare(sTool, m_MainWindow.m_CurrentMachine.ToolChanger(i).sTool) = 0 Then
            Return True
         End If
      Next
      ' Ricerca nel cambia utensili manuale
      For i As Integer = 0 To m_MainWindow.m_CurrentMachine.ManualToolChangerNbr() - 1
         If String.Compare(sTool, m_MainWindow.m_CurrentMachine.ManualToolChanger(i).sTool) = 0 Then
            Return True
         End If
      Next
      ' Non trovato
      Return False
   End Function

   Friend Function TestAllMachiningsForStrict() As Boolean
      Dim bModified As Boolean = False
      ' Affondamento ridotto
      Dim dReducedDepth As Double = GetPrivateProfileDouble(S_MACH_NEST, K_MACH_REDUCEDDEPTH, 1, m_MainWindow.GetMachIniFile())
      ' Ciclo sulle lavorazioni
      Dim nOperId As Integer = EgtGetFirstOperation()
      While nOperId <> GDB_ID.NULL
         ' verifico sia una lavorazione valida di taglio con lama
         If IsValidMachining( nOperId) And EgtGetOperationType( nOperId) = MCH_OY.SAWING Then
            ' verifica interferenza
            Dim nFlag As Integer = FMI_TYPE.NONE
            If Not VerifyComposedMachining(nOperId, nFlag) Then
               nFlag = FMI_TYPE.LI Or FMI_TYPE.RM Or FMI_TYPE.LO
            End If
            ' sistemazione lavorazione, se necessario
            If AdjustMachining(nOperId, nFlag, dReducedDepth) Then
               bModified = True
               ' se abilitato e attivo waterjet, lo aggiungo per completare il taglio
               If m_MainWindow.m_CurrentMachine.WaterJettingActive Then
                  Dim nWarn As Integer = 0
                  AddWaterJetMachining(nOperId, nWarn)
               End If
            End If
         End If
         nOperId = EgtGetNextOperation(nOperId)
      End While
      Return bModified
   End Function

   Friend Function VerifyComposedMachining(nOperId As Integer, ByRef nFlag As Integer) As Boolean
      ' verifico sia una lavorazione
      If Not EgtSetCurrMachining(nOperId) Then Return False
      ' determino eventuali lavorazioni inglobate
      Dim vOthId As New List(Of Integer)
      Dim sInfo As String = String.Empty
      If EgtGetInfo(nOperId, INFO_MCH_OTHMID, sInfo) Then
         Dim sItems() As String = sInfo.Split(",".ToCharArray)
         For Each sId As String In sItems
            Dim nId As Integer = 0
            StringToInt(sId, nId)
            If nId > 0 Then vOthId.Add(nId)
         Next
      End If
      ' layer di origine
      Dim sLay As String = String.Empty
      EgtGetInfo(nOperId, INFO_MCH_LAYER, sLay)
      ' verifica interferenza
      nFlag = FMI_TYPE.NONE
      If sLay = NAME_OUTLOOP Then
         Dim nRes As Integer = FMI_TYPE.LI Or FMI_TYPE.RM Or FMI_TYPE.LO
         If Not EgtVerifyMachining(nOperId, nRes) Then Return False
         nFlag = nFlag Or nRes
         Dim nToolInt As Integer = 0
         EgtMdbGetCurrMachiningParam(MCH_MP.LEADINTYPE, nToolInt)
         If nToolInt = Int(MCH_SAW_LI.STRICT) Then
            nFlag = nFlag Or FMI_TYPE.LI
         End If
         nToolInt = 0
         EgtMdbGetCurrMachiningParam(MCH_MP.LEADOUTTYPE, nToolInt)
         If nToolInt = Int(MCH_SAW_LO.STRICT) Then
            nFlag = nFlag Or FMI_TYPE.LO
         End If
         For Each nId As Integer In vOthId
            nRes = FMI_TYPE.LI Or FMI_TYPE.RM Or FMI_TYPE.LO
            If Not EgtVerifyMachining(nId, nRes) Then Return False
            nFlag = nFlag Or nRes
         Next
      End If
      Return True
   End Function

   Friend Function AdjustMachining(nOperId As Integer, nFlag As Integer, dReducedDepth As Double) As Boolean
      Dim bModified As Boolean = False
      ' abilitazione
      Dim bEnabled As Boolean = Not EgtExistsInfo(nOperId, INFO_MCH_USER_OFF)
      ' restringo lavorazione abilitata ma con interferenza
      If bEnabled And nFlag <> FMI_TYPE.NONE Then
         Dim bStart As Boolean = ((nFlag And FMI_TYPE.LI) <> 0)
         Dim bEnd As Boolean = ((nFlag And FMI_TYPE.LO) <> 0)
         SetCutStrict(nOperId, bStart, bEnd)
         ' se risulta lavorazione vuota, provo a diminuire l'affondamento
         If EgtIsMachiningEmpty() Then
            ResetCutStrict(nOperId, bStart, bEnd)
            SetCutDepth(nOperId, dReducedDepth)
            ' ripeto verifica
            nFlag = FMI_TYPE.NONE
            If Not VerifyComposedMachining(nOperId, nFlag) Then
               nFlag = FMI_TYPE.LI Or FMI_TYPE.RM Or FMI_TYPE.LO
            End If
            ' se non superata la stringo
            If nFlag <> FMI_TYPE.NONE Then
               bStart = ((nFlag And FMI_TYPE.LI) <> 0)
               bEnd = ((nFlag And FMI_TYPE.LO) <> 0)
               SetCutStrict(nOperId, bStart, bEnd)
            End If
         End If
         bModified = True
      End If
      Return bModified
   End Function

   Friend Function SetCutDepth(nMchId As Integer, dDepth As Double) As Boolean
      ' Imposto la lavorazione corrente
      If Not EgtSetCurrMachining(nMchId) Then Return False
      ' Imposto l'affondamento
      EgtSetMachiningParam(MCH_MP.DEPTH, dDepth)
      ' Ricalcolo il preview
      UpdateMachiningPreview(nMchId, True)
      Return True
   End Function

   Friend Function SetCutStrict(nMchId As Integer, bStart As Boolean, bEnd As Boolean) As Boolean
      ' Recupero sicurezza su tagli
      Dim dSafeLen As Double = GetPrivateProfileDouble(S_MACH_NEST, K_MACH_SAFE_LEN_CUT, 0, m_MainWindow.GetMachIniFile())
      ' Imposto la lavorazione corrente
      If Not EgtSetCurrMachining(nMchId) Then Return False
      Dim bModif As Boolean = False
      ' Se richiesto, restringo l'attacco
      If bStart Then
         ' Recupero tipo attacco originale e lo salvo se non già fatto
         Dim nOriLeadIn As Integer = MCH_SAW_LI.CENT
         EgtGetMachiningParam(MCH_MP.LEADINTYPE, nOriLeadIn)
         If Not EgtExistsInfo(nMchId, INFO_MCH_ORILEADIN) Then
            EgtSetInfo(nMchId, INFO_MCH_ORILEADIN, nOriLeadIn)
         End If
         ' Se attacco cambiato, aggiorno e accorcio della sicurezza sui tagli
         If nOriLeadIn <> MCH_SAW_LI.STRICT Then
            EgtSetMachiningParam(MCH_MP.LEADINTYPE, MCH_SAW_LI.STRICT)
            Dim dUserAddLen As Double = 0
            EgtGetInfo( nMchId, INFO_MCH_USER_SAL, dUserAddLen)
            EgtRemoveInfo( nMchId, INFO_MCH_USER_SAL)
            Dim dAddLen As Double = 0
            EgtGetMachiningParam(MCH_MP.STARTADDLEN, dAddLen)
            EgtSetMachiningParam(MCH_MP.STARTADDLEN, dAddLen - dUserAddLen - dSafeLen)
            bModif = True
         End If
      End If
      ' Se richiesto, restringo l'uscita
      If bEnd Then
         ' Recupero tipo uscita originale e lo salvo se non già fatto
         Dim nOriLeadOut As Integer = MCH_SAW_LO.CENT
         EgtGetMachiningParam(MCH_MP.LEADOUTTYPE, nOriLeadOut)
         If Not EgtExistsInfo(nMchId, INFO_MCH_ORILEADOUT) Then
            EgtSetInfo(nMchId, INFO_MCH_ORILEADOUT, nOriLeadOut)
         End If
         ' Se uscita cambiata, aggiorno e accorcio della sicurezza sui tagli
         If nOriLeadOut <> MCH_SAW_LO.STRICT Then
            EgtSetMachiningParam(MCH_MP.LEADOUTTYPE, MCH_SAW_LO.STRICT)
            Dim dUserAddLen As Double = 0
            EgtGetInfo( nMchId, INFO_MCH_USER_EAL, dUserAddLen)
            EgtRemoveInfo( nMchId, INFO_MCH_USER_EAL)
            Dim dAddLen As Double = 0
            EgtGetMachiningParam(MCH_MP.ENDADDLEN, dAddLen)
            EgtSetMachiningParam(MCH_MP.ENDADDLEN, dAddLen - dUserAddLen - dSafeLen)
            bModif = True
         End If
      End If
      ' Se modificato, ricalcolo il preview
      If bModif Then
         UpdateMachiningPreview(nMchId, True)
      End If
      Return True
   End Function

   Friend Function ResetCutStrict(nMchId As Integer, bStart As Boolean, bEnd As Boolean) As Boolean
      ' Recupero sicurezza su tagli
      Dim dSafeLen As Double = GetPrivateProfileDouble(S_MACH_NEST, K_MACH_SAFE_LEN_CUT, 0, m_MainWindow.GetMachIniFile())
      ' Imposto la lavorazione corrente
      If Not EgtSetCurrMachining(nMchId) Then Return False
      Dim bModif As Boolean = False
      ' Se richiesto, ripristino l'attacco
      If bStart Then
         ' Recupero tipo attacco originale
         Dim nOriLeadIn As Integer = MCH_SAW_LI.CENT
         EgtGetInfo(nMchId, INFO_MCH_ORILEADIN, nOriLeadIn)
         Dim nCurrLeadIn As Integer = MCH_SAW_LI.CENT
         EgtGetMachiningParam(MCH_MP.LEADINTYPE, nCurrLeadIn)
         ' Se attacco cambiato, aggiorno e allungo della sicurezza sui tagli
         If nOriLeadIn <> nCurrLeadIn Then
            EgtSetMachiningParam(MCH_MP.LEADINTYPE, nOriLeadIn)
            Dim dAddLen As Double = 0
            EgtGetMachiningParam(MCH_MP.STARTADDLEN, dAddLen)
            EgtSetMachiningParam(MCH_MP.STARTADDLEN, dAddLen + dSafeLen)
            bModif = True
         End If
      End If
      ' Se richiesto, ripristino l'uscita
      If bEnd Then
         ' Recupero tipo uscita originale
         Dim nOriLeadOut As Integer = MCH_SAW_LO.CENT
         EgtGetInfo(nMchId, INFO_MCH_ORILEADOUT, nOriLeadOut)
         Dim nCurrLeadOut As Integer = MCH_SAW_LO.CENT
         EgtGetMachiningParam(MCH_MP.LEADOUTTYPE, nCurrLeadOut)
         ' Se uscita cambiata, aggiorno
         If nOriLeadOut <> nCurrLeadOut Then
            EgtSetMachiningParam(MCH_MP.LEADOUTTYPE, nOriLeadOut)
            Dim dAddLen As Double = 0
            EgtGetMachiningParam(MCH_MP.ENDADDLEN, dAddLen)
            EgtSetMachiningParam(MCH_MP.ENDADDLEN, dAddLen + dSafeLen)
            bModif = True
         End If
      End If
      ' Se modificato, ricalcolo il preview
      If bModif Then
         UpdateMachiningPreview(nMchId, True)
      End If
      Return True
   End Function

   Friend Function SetPause(nMchId As Integer) As Boolean
      Return EgtSetInfo(nMchId, INFO_MCH_PAUSE, True)
   End Function

   Friend Function GetPause(nMchId As Integer) As Boolean
      Dim bPause As Boolean = False
      EgtGetInfo(nMchId, INFO_MCH_PAUSE, bPause)
      Return bPause
   End Function

   Friend Function ResetPause(nMchId As Integer) As Boolean
      Return EgtRemoveInfo(nMchId, INFO_MCH_PAUSE)
   End Function

   Friend Function SetEnableInvert(nEntId As Integer) As Boolean
      Return EgtRemoveInfo(nEntId, INFO_ENABLE_INVERT)
   End Function

   Friend Function GetEnableInvert(nEntId As Integer) As Boolean
      Dim bEnable As Boolean = True
      EgtGetInfo(nEntId, INFO_ENABLE_INVERT, bEnable)
      Return bEnable
   End Function

   Friend Function ResetEnableInvert(nEntId As Integer) As Boolean
      Return EgtSetInfo(nEntId, INFO_ENABLE_INVERT, False)
   End Function

   Friend Function UpdateMachiningPreview(nMchId As Integer, bMoveOnPart As Boolean) As Boolean
      ' Imposto la lavorazione corrente
      If Not EgtSetCurrMachining(nMchId) Then Return False
      ' Ricalcolo il preview
      EgtPreviewMachining(True)
      ' Se non devo spostarlo nel pezzo, esco
      If Not bMoveOnPart Then Return True
      ' Indice gruppo di preview nella lavorazione
      Dim nMchPvId As Integer = EgtGetFirstNameInGroup(nMchId, NAME_PREVIEW)
      ' Indice gruppo di preview nel pezzo
      Dim nPartPvId As Integer = GDB_ID.NULL
      EgtGetInfo(nMchPvId, INFO_PV_ONPART_ID, nPartPvId)
      ' Svuoto il preview nel pezzo
      EgtEmptyGroup(nPartPvId)
      ' Rimuovo anche il preview di lavorazioni inglobate
      Dim sInfo As String = String.Empty
      If EgtGetInfo(nMchId, INFO_MCH_OTHMID, sInfo) Then
         Dim sItems() As String = sInfo.Split(",".ToCharArray)
         For Each sId2 As String In sItems
            ' Indice gruppo di preview nella lavorazione
            Dim nId2 As Integer = GDB_ID.NULL
            StringToInt(sId2, nId2)
            Dim nMchPvId2 As Integer = EgtGetFirstNameInGroup(nId2, NAME_PREVIEW)
            ' Indice gruppo di preview nel pezzo
            Dim nPartPvId2 As Integer = GDB_ID.NULL
            EgtGetInfo(nMchPvId2, INFO_PV_ONPART_ID, nPartPvId2)
            ' Svuoto il preview nel pezzo
            EgtEmptyGroup(nPartPvId2)
         Next
      End If
      ' Lo sposto dalla lavorazione al pezzo
      Dim nId As Integer = EgtGetFirstInGroup(nMchPvId)

      If nId = GDB_ID.NULL Then Return False

      While nId <> GDB_ID.NULL
         EgtRelocateGlob(nId, nPartPvId)
         nId = EgtGetFirstInGroup(nMchPvId)
      End While
      Return True
   End Function

   Friend Function RemoveMachiningPreview(nMchId As Integer) As Boolean
      ' Indice gruppo di preview nella lavorazione
      Dim nMchPvId As Integer = EgtGetFirstNameInGroup(nMchId, NAME_PREVIEW)
      ' Lo svuoto
      Return EgtEmptyGroup(nMchPvId)
   End Function

   Friend Function IsValidMachining(nOperId As Integer) As Boolean
      ' Deve essere una lavorazione
      If Not EgtSetCurrMachining(nOperId) Then Return False
      ' Deve contenere qualcosa
      If EgtIsMachiningEmpty() Then Return False
      ' Deve essere abilitata oppure disabilitata direttamente dall'utente
      If Not (EgtGetOperationMode(nOperId) Or EgtExistsInfo(nOperId, INFO_MCH_USER_OFF)) Then Return False
      ' E' valida
      Return True
   End Function

   Friend Function IsExitPreCut(nOperId As Integer) As Boolean
      ' Deve essere una lavorazione
      If Not EgtSetCurrMachining(nOperId) Then Return False
      ' Verifico presenza Info di PreCut
      Return EgtExistsInfo(nOperId, INFO_MCH_EPC)
   End Function

   Friend Function RemoveAllExitPreCuts() As Boolean
      Dim nOperId As Integer = EgtGetFirstOperation()
      While nOperId <> GDB_ID.NULL
         Dim nNextOperId As Integer = EgtGetNextOperation( nOperId)
         If EgtGetType( nOperId) <> MCH_OY.DISP AndAlso EgtExistsInfo(nOperId, INFO_MCH_EPC) Then
            EgtRemoveOperation( nOperId)
         End If
         nOperId = nNextOperId
      End While
      Return True
   End Function

   Private Function SetLuaStandardCamParams(Optional bDripOk As Boolean = True) As Boolean
      Dim sMaterial As String = m_MainWindow.m_CurrentMachine.CurrMat.sName
      Dim sSawMch As String = m_MainWindow.m_CurrentMachine.sCurrSawing
      Dim sMillMch As String = m_MainWindow.m_CurrentMachine.sCurrMilling
      Dim sDrillMch As String = m_MainWindow.m_CurrentMachine.sCurrDrilling
      Dim sWaterJetMch As String = m_MainWindow.m_CurrentMachine.sCurrWaterJetting
      Dim sWaterJetQual As String = m_MainWindow.m_CurrentMachine.sCurrWaterJettingQuality
      Dim sPocketMch As String = m_MainWindow.m_CurrentMachine.sCurrPocketing
      Dim sDripSawMch As String = If(bDripOk, m_MainWindow.m_CurrentMachine.sCurrDripSawing, "")
      Dim sDripDrillMch As String = If(bDripOk, m_MainWindow.m_CurrentMachine.sCurrDripDrilling, "")
      Dim dReducedDepth As Double = GetPrivateProfileDouble(S_MACH_NEST, K_MACH_REDUCEDDEPTH, 1, m_MainWindow.GetMachIniFile())
      Dim dHolesOffset As Double = GetPrivateProfileDouble(S_MACH_NEST, K_MACH_HOLES_OFFSET, 0, m_MainWindow.GetMachIniFile())
      Dim dHolesOverlap As Double = GetPrivateProfileDouble(S_MACH_NEST, K_MACH_HOLES_OVERLAP, 0, m_MainWindow.GetMachIniFile())
      Dim dCutSafety As Double = Math.Max(GetPrivateProfileDouble(S_MACH_NEST, K_MACH_SAFE_LEN_CUT, 1, m_MainWindow.GetMachIniFile()), 10 * EPS_SMALL)
      Dim dCornerSafety As Double = Math.Max(GetPrivateProfileDouble(S_MACH_NEST, K_MACH_SAFE_LEN_INTCORNER, 1, m_MainWindow.GetMachIniFile()), 10 * EPS_SMALL)
      Dim bOneHoleIntCorner As Boolean = (GetPrivateProfileInt(S_MACH_NEST, K_MACH_ONEHOLE_INTCORNER, 0, m_MainWindow.GetMachIniFile()) <> 0)
      Dim bMillingOnCorners As Boolean = (GetPrivateProfileInt(S_MACH_NEST, K_MACH_MILLING_ON_CORNERS, 1, m_MainWindow.GetMachIniFile()) <> 0)
      Dim bMillingOnSinks As Boolean = (GetPrivateProfileInt(S_MACH_NEST, K_MACH_MILLING_ON_SINKS, 0, m_MainWindow.GetMachIniFile()) <> 0)
      Dim dMillingShort As Double = GetPrivateProfileDouble(S_MACH_NEST, K_MACH_MILLING_SHORTENING, 0, m_MainWindow.GetMachIniFile())
      EgtLuaSetGlobStringVar("CAM.MATERIAL", sMaterial)
      EgtLuaSetGlobStringVar("CAM.SAWMCH", sSawMch)
      EgtLuaSetGlobStringVar("CAM.MILLMCH", sMillMch)
      EgtLuaSetGlobStringVar("CAM.DRILLMCH", sDrillMch)
      EgtLuaSetGlobStringVar("CAM.POCKETMCH", sPocketMch)
      EgtLuaSetGlobStringVar("CAM.WATERJETMCH", sWaterJetMch)
      EgtLuaSetGlobStringVar("CAM.WATERJETQLTY", sWaterJetQual)
      EgtLuaSetGlobStringVar("CAM.DRIPSAWMCH", sDripSawMch)
      EgtLuaSetGlobStringVar("CAM.DRIPDRILLMCH", sDripDrillMch)
      EgtLuaSetGlobNumVar("CAM.REDUCEDDEPTH", dReducedDepth)
      EgtLuaSetGlobNumVar("CAM.HOLESOFFSET", dHolesOffset)
      EgtLuaSetGlobNumVar("CAM.HOLESOVERLAP", dHolesOverlap)
      EgtLuaSetGlobBoolVar("CAM.ONEHOLEINTCORNER", bOneHoleIntCorner)
      EgtLuaSetGlobNumVar("CAM.CUTSAFETY", dCutSafety)
      EgtLuaSetGlobNumVar("CAM.CORNERSAFETY", dCornerSafety)
      EgtLuaSetGlobBoolVar("CAM.MILLINGONCORNERS", bMillingOnCorners)
      EgtLuaSetGlobBoolVar("CAM.MILLINGONSINKS", bMillingOnSinks)
      EgtLuaSetGlobNumVar("CAM.MILLINGSHORT", dMillingShort)
      EgtLuaSetGlobNumVar("CAM.RAWHEIGHT", GetRawHeight())
      EgtLuaSetGlobNumVar("CAM.REGROT", GetRegistrationRotation())
      Return True
   End Function

   Friend Function GetTableCount() As Integer
      If EgtGetTableId(MAIN_TAB) = GDB_ID.NULL Then Return 0
      If EgtGetTableId(SECOND_TAB) = GDB_ID.NULL Then Return 1
      If EgtGetTableId(THIRD_TAB) = GDB_ID.NULL Then Return 2
      Return 3
   End Function

   Friend Function GetTableName(nInd As Integer) As String
      If nInd = 1 Then Return MAIN_TAB
      If nInd = 2 Then Return SECOND_TAB
      If nInd = 3 Then Return THIRD_TAB
      Return ""
   End Function

   Friend Function GetCurrentTable() As Integer
      Dim sTabName As String = MAIN_TAB
      EgtGetTableName(sTabName)
      If sTabName = THIRD_TAB Then
         Return 3
      ElseIf sTabName = SECOND_TAB Then
         Return 2
      Else
         Return 1
      End If
   End Function

   Friend Function GetCurrentRaw() As Integer
      ' Recupero il grezzo (primo con fase 1)
      Dim nRawId As Integer = EgtGetFirstRawPart()
      While nRawId <> GDB_ID.NULL And Not EgtVerifyRawPartPhase(nRawId, 1)
         nRawId = EgtGetNextRawPart(nRawId)
      End While
      Return nRawId
   End Function

   Friend Function GetRawBox(ByRef ptRawMin As Point3d, ByRef ptRawMax As Point3d) As Boolean
      Return EgtGetRawPartBBox(GetCurrentRaw(), ptRawMin, ptRawMax)
   End Function

   Friend Function GetRawBox(ByRef b3RawBox As BBox3d) As Boolean
      Return EgtGetRawPartBBox(GetCurrentRaw(), b3RawBox)
   End Function

   Friend Function GetRawCenter(ByRef ptCent As Point3d) As Boolean
      Return EgtGetRawPartCenter(GetCurrentRaw(), ptCent)
   End Function

   Friend Function GetRawHeight() As Double
      Dim ptRawMin, ptRawMax As Point3d
      If GetRawBox(ptRawMin, ptRawMax) Then
         Return (ptRawMax.z - ptRawMin.z)
      Else
         Return 0
      End If
   End Function

   Friend Function SetRegistrationRotation(dRegRot As Double) As Boolean
      Return EgtSetInfo(GetCurrentRaw(), INFO_REGROT, dRegRot)
   End Function

   Friend Function ResetRegistrationRotation() As Boolean
      Return EgtRemoveInfo(GetCurrentRaw(), INFO_REGROT)
   End Function

   Friend Function GetRegistrationRotation() As Double
      Dim dRegRot As Double = 0
      EgtGetInfo(GetCurrentRaw(), INFO_REGROT, dRegRot)
      Return dRegRot
   End Function

   Friend Function UpdateAllRawsZ(dDeltaZ As Double) As Boolean
      For i As Integer = 1 To EgtGetPhaseCount()
         EgtSetCurrPhase(i)
         Dim nRawId As Integer = EgtGetFirstRawPart()
         While nRawId <> GDB_ID.NULL
            If EgtVerifyRawPartCurrPhase(nRawId) Then
               EgtMoveRawPart(nRawId, New Vector3d(0, 0, dDeltaZ))
            End If
            nRawId = EgtGetNextRawPart(nRawId)
         End While
      Next
      EgtSetCurrPhase(1)
      HideAllMachinings()
      Return True
   End Function

   Friend Function IsMachiningInActiveRaw(nMchId As Integer) As Boolean
      EgtSetCurrMachining(nMchId)
      ' Recupero la prima entità geometrica della lavorazione
      Dim nId, nSub As Integer
      If Not EgtGetMachiningGeometry(0, nId, nSub) Then Return False
      ' Recupero il pezzo di appartenenza
      Dim nPartId = EgtGetParent(EgtGetParent(nId))
      If nPartId = GDB_ID.NULL Then Return False
      ' Recupero la fase di appartenenza della lavorazione
      Dim nPhase As Integer = EgtGetOperationPhase(nMchId)
      ' Verifico se il pezzo è nei grezzi della fase indicata
      Dim nRawId As Integer = EgtGetFirstRawPart()
      While nRawId <> GDB_ID.NULL
         If EgtVerifyRawPartPhase(nRawId, nPhase) Then
            Dim nPirId As Integer = EgtGetFirstPartInRawPart(nRawId)
            While nPirId <> GDB_ID.NULL
               If nPartId = nPirId Then Return True
               nPirId = EgtGetNextPartInRawPart(nPirId)
            End While
         End If
         nRawId = EgtGetNextRawPart(nRawId)
      End While
      Return False
   End Function

   Friend Function AddFrameMachinings(dTrimStart As Double, dTrimEnd As Double) As Boolean
      ' Cancello tutte le lavorazioni
      EgtRemoveAllOperations()
      ' Recupero il grezzo corrente
      Dim nRawId As Integer = GetCurrentRaw()
      If nRawId = GDB_ID.NULL Then Return False
      ' Se non ci sono pezzi, esco
      If EgtGetPartInRawPartCount(nRawId) = 0 Then Return True
      ' Aggiungo sgrossatura
      If Not AddFrameSawRoughing(dTrimStart, dTrimEnd) Then Return False
      ' Aggiungo finitura
      If Not AddFrameSawFinishing(dTrimStart, dTrimEnd) Then Return False
      ' Aggiungo spatolatura
      If Not AddFrameSawSideFinishing(dTrimStart, dTrimEnd) Then Return False
      ' Aggiungo taglio singolo
      If Not AddFrameSawSingle() Then Return False
      Return True
   End Function

   Friend Function AddFrameSawRoughing(dTrimStart As Double, dTrimEnd As Double) As Boolean
      ' Cancello la lavorazione di sgrossatura
      Dim nId As Integer = EgtGetOperationId(NAME_FRAME_SAWROU)
      EgtRemoveOperation(nId)
      ' Recupero il grezzo corrente
      Dim nRawId As Integer = GetCurrentRaw()
      If nRawId = GDB_ID.NULL Then Return False
      ' Se non ci sono pezzi, esco
      Dim nPart1Id As Integer = EgtGetFirstPartInRawPart( nRawId)
      If nPart1Id = GDB_ID.NULL Then Return True
      ' Verifico se cornice curva
      Dim nDir As Integer = 0
      EgtGetInfo(nPart1Id, INFO_FRAME_DIR, nDir)
      Dim bSwap As Boolean = ( nDir = 0)
      Dim bCurved As Boolean = ( nDir >= 2)
      ' Recupero la lavorazione corrente di sgrossatura con lama
      Dim sCurrSawRoughing = m_MainWindow.m_CurrentMachine.sCurrSawRoughing
      If String.IsNullOrEmpty(sCurrSawRoughing) Then Return True
      ' Inserisco la lavorazione corrente
      Dim nMchId As Integer = EgtAddMachining(NAME_FRAME_SAWROU, sCurrSawRoughing)
      If nMchId = GDB_ID.NULL Then Return False
      ' La sposto all'inizio delle lavorazioni (subito dopo la disposizione)
      Dim nDispId As Integer = EgtGetPhaseDisposition(1)
      If Not EgtRelocate(nMchId, nDispId, GDB_POS.AFTER) Then
         EgtErase(nMchId)
         Return False
      End If
      ' Recupero sezioni e prima guida dei pezzi nel grezzo
      Dim nCount As Integer = EgtGetPartInRawPartCount(nRawId)
      Dim vId(nCount) As Integer
      Dim nInd As Integer = 0
      Dim nPartId As Integer = EgtGetFirstPartInRawPart(nRawId)
      vId(nCount) = EgtGetFirstInGroup(EgtGetFirstNameInGroup(nPartId, NAME_GUIDE))
      While nPartId <> GDB_ID.NULL
         vId(nInd) = EgtGetFirstInGroup(EgtGetFirstNameInGroup(nPartId, NAME_SECT))
         nInd += 1
         nPartId = EgtGetNextPartInRawPart(nPartId)
      End While
      ' Imposto la geometria
      EgtSetMachiningGeometry(vId)
      ' Imposto trim iniziale e finale
      EgtSetMachiningParam(MCH_MP.STARTADDLEN, If( bSwap, -dTrimEnd, -dTrimStart))
      EgtSetMachiningParam(MCH_MP.ENDADDLEN, If( bSwap, -dTrimStart, -dTrimEnd))
      ' Se cornice curva, imposto SCC
      If bCurved Then EgtSetMachiningParam(MCH_MP.SOLCHOICETYPE, MCH_SCC.ADIR_NEAR)
      ' Applico la lavorazione
      Return EgtApplyMachining(False)
   End Function

   Friend Function AddFrameSawFinishing(dTrimStart As Double, dTrimEnd As Double) As Boolean
      ' Cancello la lavorazione di finitura
      Dim nId As Integer = EgtGetOperationId(NAME_FRAME_SAWFIN)
      EgtRemoveOperation(nId)
      ' Recupero il grezzo corrente
      Dim nRawId As Integer = GetCurrentRaw()
      If nRawId = GDB_ID.NULL Then Return False
      ' Se non ci sono pezzi, esco
      Dim nPart1Id As Integer = EgtGetFirstPartInRawPart( nRawId)
      If nPart1Id = GDB_ID.NULL Then Return True
      ' Verifico se cornice curva
      Dim nDir As Integer = 0
      EgtGetInfo( nPart1Id, INFO_FRAME_DIR, nDir)
      Dim bSwap As Boolean = ( nDir = 0)
      Dim bCurved As Boolean = ( nDir >= 2)
      ' Recupero la lavorazione corrente di finitura con lama
      Dim sCurrSawFinishing = m_MainWindow.m_CurrentMachine.sCurrSawFinishing
      If String.IsNullOrEmpty(sCurrSawFinishing) Then Return True
      ' Inserisco la lavorazione corrente
      Dim nMchId As Integer = EgtAddMachining(NAME_FRAME_SAWFIN, sCurrSawFinishing)
      If nMchId = GDB_ID.NULL Then Return False
      ' La sposto prima di una eventuale spatolatura
      Dim nSideFinId As Integer = EgtGetFirstOperation()
      While nSideFinId <> GDB_ID.NULL
         Dim sName As String = String.Empty
         If EgtGetOperationName(nSideFinId, sName) AndAlso
            String.Compare(sName, NAME_FRAME_SAWSIDEFIN, True) = 0 Then
            Exit While
         End If
         nSideFinId = EgtGetNextOperation(nSideFinId)
      End While
      If nSideFinId <> GDB_ID.NULL Then
         If Not EgtRelocate(nMchId, nSideFinId, GDB_POS.BEFORE) Then
            EgtErase(nMchId)
            Return False
         End If
      End If
      ' Recupero sezioni e prima guida dei pezzi nel grezzo
      Dim nCount As Integer = EgtGetPartInRawPartCount(nRawId)
      Dim vId(nCount) As Integer
      Dim nInd As Integer = 0
      Dim nPartId As Integer = EgtGetFirstPartInRawPart(nRawId)
      vId(nCount) = EgtGetFirstInGroup(EgtGetFirstNameInGroup(nPartId, NAME_GUIDE))
      While nPartId <> GDB_ID.NULL
         vId(nInd) = EgtGetFirstInGroup(EgtGetFirstNameInGroup(nPartId, NAME_SECT))
         nInd += 1
         nPartId = EgtGetNextPartInRawPart(nPartId)
      End While
      ' Imposto la geometria
      EgtSetMachiningGeometry(vId)
      ' Imposto trim iniziale e finale
      EgtSetMachiningParam(MCH_MP.STARTADDLEN, If( bSwap, -dTrimEnd, -dTrimStart))
      EgtSetMachiningParam(MCH_MP.ENDADDLEN, If( bSwap, -dTrimStart, -dTrimEnd))
      ' Se cornice curva, imposto SCC
      If bCurved Then EgtSetMachiningParam(MCH_MP.SOLCHOICETYPE, MCH_SCC.ADIR_NEAR)
      ' Applico la lavorazione
      Return EgtApplyMachining(False)
   End Function

   Friend Function AddFrameSawSideFinishing(dTrimStart As Double, dTrimEnd As Double) As Boolean
      ' Cancello la lavorazione di spatolatura
      Dim nId As Integer = EgtGetOperationId(NAME_FRAME_SAWSIDEFIN)
      EgtRemoveOperation(nId)
      ' Recupero il grezzo corrente
      Dim nRawId As Integer = GetCurrentRaw()
      If nRawId = GDB_ID.NULL Then Return False
      ' Se non ci sono pezzi, esco
      Dim nPart1Id As Integer = EgtGetFirstPartInRawPart( nRawId)
      If nPart1Id = GDB_ID.NULL Then Return True
      ' Verifico se cornice curva
      Dim nDir As Integer = 0
      EgtGetInfo(nPart1Id, INFO_FRAME_DIR, nDir)
      Dim bSwap As Boolean = ( nDir = 0)
      Dim bCurved As Boolean = ( nDir >= 2)
      ' Recupero la lavorazione corrente di spatolatura con lama
      Dim sCurrSawSideFinishing = m_MainWindow.m_CurrentMachine.sCurrSawSideFinishing
      If String.IsNullOrEmpty(sCurrSawSideFinishing) Then Return True
      ' Inserisco la lavorazione corrente
      Dim nMchId As Integer = EgtAddMachining(NAME_FRAME_SAWSIDEFIN, sCurrSawSideFinishing)
      If nMchId = GDB_ID.NULL Then Return False
      ' Recupero sezioni e prima guida dei pezzi nel grezzo
      Dim nCount As Integer = EgtGetPartInRawPartCount(nRawId)
      Dim vId(nCount) As Integer
      Dim nInd As Integer = 0
      Dim nPartId As Integer = EgtGetFirstPartInRawPart(nRawId)
      vId(nCount) = EgtGetFirstInGroup(EgtGetFirstNameInGroup(nPartId, NAME_GUIDE))
      While nPartId <> GDB_ID.NULL
         vId(nInd) = EgtGetFirstInGroup(EgtGetFirstNameInGroup(nPartId, NAME_SECT))
         nInd += 1
         nPartId = EgtGetNextPartInRawPart(nPartId)
      End While
      ' Imposto la geometria
      EgtSetMachiningGeometry(vId)
      ' Imposto trim iniziale e finale
      EgtSetMachiningParam(MCH_MP.STARTADDLEN, If( bSwap, -dTrimEnd, -dTrimStart))
      EgtSetMachiningParam(MCH_MP.ENDADDLEN, If( bSwap, -dTrimStart, -dTrimEnd))
      ' Se cornice curva, imposto SCC
      If bCurved Then EgtSetMachiningParam(MCH_MP.SOLCHOICETYPE, MCH_SCC.ADIR_NEAR)
      ' Applico la lavorazione
      Return EgtApplyMachining(False)
   End Function

   Friend Function AddFrameSawSingle() As Boolean
      ' Cancello la lavorazione di taglio singolo
      Dim nId As Integer = EgtGetOperationId(NAME_FRAME_SAWSINGLE)
      EgtRemoveOperation(nId)
      ' Recupero il grezzo corrente
      Dim nRawId As Integer = GetCurrentRaw()
      Dim nSolidId As Integer = EgtGetFirstNameInGroup(nRawId, NAME_RAW_SOLID)
      If nRawId = GDB_ID.NULL Or nSolidId = GDB_ID.NULL Then Return False
      Dim b3Raw As New BBox3d
      GetRawBox(b3Raw)
      ' Se non ci sono pezzi, esco
      If EgtGetPartInRawPartCount(nRawId) = 0 Then Return True
      ' Recupero la lavorazione corrente di taglio singolo con lama
      Dim sCurrSawSingle = m_MainWindow.m_CurrentMachine.sCurrSawSingle
      If String.IsNullOrEmpty(sCurrSawSingle) Then Return True
      ' Creo la lavorazione a partire dalla corrente
      If Not EgtMdbSetCurrMachining(sCurrSawSingle) Then Return False
      Dim sTuuid As String = String.Empty
      Dim sTool As String = String.Empty
      EgtMdbGetCurrMachiningParam(MCH_MP.TUUID, sTuuid)
      EgtTdbGetToolFromUUID(sTuuid, sTool)
      EgtTdbSetCurrTool(sTool)
      Dim dMaxMat As Double = 50
      EgtTdbGetCurrToolParam(MCH_TP.MAXMAT, dMaxMat)
      Dim dTDiam As Double = 200
      EgtTdbGetCurrToolParam(MCH_TP.DIAM, dTDiam)
      Dim nStepType As Integer = MCH_SAW_ST.ZIGZAG
      EgtMdbGetCurrMachiningParam(MCH_MP.STEPTYPE, nStepType)
      Dim dStep As Double = 0
      EgtMdbGetCurrMachiningParam(MCH_MP.STEP_, dStep)
      Dim nLiType As Integer = MCH_SAW_LI.CENT
      EgtMdbGetCurrMachiningParam(MCH_MP.LEADINTYPE, nLiType)
      Dim nLoType As Integer = MCH_SAW_LO.CENT
      EgtMdbGetCurrMachiningParam(MCH_MP.LEADOUTTYPE, nLoType)
      Dim dSpeed As Double = 0
      EgtMdbGetCurrMachiningParam(MCH_MP.SPEED, dSpeed)
      Dim dFeed As Double = 0
      EgtMdbGetCurrMachiningParam(MCH_MP.FEED, dFeed)
      Dim dStartFeed As Double = 0
      EgtMdbGetCurrMachiningParam(MCH_MP.STARTFEED, dStartFeed)
      Dim dEndFeed As Double = 0
      EgtMdbGetCurrMachiningParam(MCH_MP.ENDFEED, dEndFeed)
      Dim dTipFeed As Double = 0
      EgtMdbGetCurrMachiningParam(MCH_MP.TIPFEED, dTipFeed)
      Dim nMchId As Integer = EgtCreateMachining(NAME_FRAME_SAWSINGLE, MCH_MY.MILLING, sTool)
      If nMchId = GDB_ID.NULL Then Return False
      ' Recupero Id superficie e Ind facet
      Dim nSurfId As Integer = GDB_ID.NULL
      Dim nFacetInd As Integer = -1
      Dim nPirId As Integer = EgtGetFirstPartInRawPart(nRawId)
      While nPirId <> GDB_ID.NULL
         If EgtGetInfo(nPirId, INFO_FRAME_SURF, nSurfId) And
            EgtGetInfo(nPirId, INFO_FRAME_FACET, nFacetInd) Then
            Exit While
         End If
         nPirId = EgtGetNextPartInRawPart(nPirId)
      End While
      ' Recupero dati facet
      Dim ptCen As Point3d
      Dim vtN As Vector3d
      If Not EgtSurfTmFacetCenter(nSurfId, nFacetInd, GDB_ID.ROOT, ptCen, vtN) Then Return False
      ' Imposto la geometria
      EgtSetMachiningGeometry({nSurfId}, {nFacetInd})
      ' Calcolo adiacenze
      Dim vAdj As New List(Of Integer)
      If Not EgtSurfTmFacetAdjacencies(nSurfId, nFacetInd, vAdj) Then Return False
      ' Verifico facce adiacenti
      Dim ptAdjCen As Point3d
      Dim vtAdjN As Vector3d = Vector3d.NULL
      For Each nAdj As Integer In vAdj
         ' Ciclo sulle adiacenze del solo primo loop (esterno)
         If nAdj = STM_FACETADJ_ENDLOOP Then Exit For
         ' Verifico tipo di adiacenza
         Dim bAdj As Boolean = False
         Dim ptP1 As Point3d
         Dim ptP2 As Point3d
         Dim dAng As Double
         If Not EgtSurfTmFacetsContact(nSurfId, nFacetInd, nAdj, GDB_ID.ROOT, bAdj, ptP1, ptP2, dAng) Then Return False
         If dAng < 0 Then
            ' Non sono ammesse due facce limitanti
            If Not vtAdjN.IsSmall() Then Return False
            ' Recupero la normale della faccia limitante
            If Not EgtSurfTmFacetCenter(nSurfId, nAdj, GDB_ID.ROOT, ptAdjCen, vtAdjN) Then Return False
         End If
      Next
      ' Proprietà faccia
      Dim bHorizz As Boolean = (Math.Abs(vtN.x) < EPS_SMALL And Math.Abs(vtN.y) < EPS_SMALL)
      Dim bFree As Boolean = (vtAdjN.IsSmall() OrElse (ptCen.z > ptAdjCen.z And vtN.z > -EPS_SMALL))
      Dim bLeftSide As Boolean = (vtN.z >= -EPS_SMALL)
      Dim dElev As Double = 0
      Dim dStartDist As Double = 0
      Dim dEndDist As Double = 0
      ' Se faccia orizzontale non limitata da altre o sopra la limitante
      If bHorizz And bFree Then
         ' recupero ingombro della faccia
         Dim nCopyId As Integer = EgtCopySurfTmFacet(nSurfId, nFacetInd, EgtGetParent(nSurfId))
         If nCopyId = GDB_ID.NULL Then Return False
         Dim b3Copy As New BBox3d
         EgtGetBBoxGlob(nCopyId, GDB_BB.STANDARD, b3Copy)
         EgtErase(nCopyId)
         If b3Copy.IsEmpty() Then Return False
         ' assegno parametri lavorazione faccia
         If b3Copy.DimY() >= b3Copy.DimX() Then
            If (b3Raw.Max().x - b3Copy.Min().x) <= (b3Copy.Max().x - b3Raw.Min().x) Then
               EgtSetMachiningParam(MCH_MP.FACEUSE, MCH_MIL_FU.ORTUP_LEFT)
               dElev = b3Raw.Max().x - b3Copy.Min().x
               dStartDist = b3Raw.Max().y - b3Copy.Max().y
               dEndDist = b3Copy.Min().y - b3Raw.Min().y
            Else
               EgtSetMachiningParam(MCH_MP.FACEUSE, MCH_MIL_FU.ORTUP_RIGHT)
               dElev = b3Copy.Max().x - b3Raw.Min().x
               dStartDist = b3Copy.Min().y - b3Raw.Min().y
               dEndDist = b3Raw.Max().y - b3Copy.Max().y
            End If
         Else
            If (b3Raw.Max().y - b3Copy.Min().y) <= (b3Copy.Max().y - b3Raw.Min().y) Then
               EgtSetMachiningParam(MCH_MP.FACEUSE, MCH_MIL_FU.ORTUP_FRONT)
               dElev = b3Raw.Max().y - b3Copy.Min().y
               dStartDist = b3Copy.Min().x - b3Raw.Min().x
               dEndDist = b3Raw.Max().x - b3Copy.Max().x
            Else
               EgtSetMachiningParam(MCH_MP.FACEUSE, MCH_MIL_FU.ORTUP_BACK)
               dElev = b3Copy.Max().y - b3Raw.Min().y
               dStartDist = b3Raw.Max().x - b3Copy.Max().x
               dEndDist = b3Copy.Min().x - b3Raw.Min().x
            End If
         End If
         If Not bLeftSide Then
            Dim dTemp As Double = dStartDist
            dStartDist = dEndDist
            dEndDist = dTemp
         End If
      ' altrimenti
      Else
         Dim vtSide As Vector3d
         ' Se faccia non limitata da altre o sopra la limitante
         If bFree Then
            EgtSetMachiningParam(MCH_MP.FACEUSE, MCH_MIL_FU.ORTUP_DOWN)
            vtSide = Vector3d.Z_AX()
         ' altrimenti è stata trovata una faccia adiacente limitante
         Else
            If vtAdjN.x > 10 * EPS_SMALL Then
               EgtSetMachiningParam(MCH_MP.FACEUSE, MCH_MIL_FU.ORTUP_LEFT)
               vtSide = Vector3d.X_AX()
            ElseIf vtAdjN.x < -10 * EPS_SMALL Then
               EgtSetMachiningParam(MCH_MP.FACEUSE, MCH_MIL_FU.ORTUP_RIGHT)
               vtSide = -Vector3d.X_AX()
            ElseIf vtAdjN.y > 10 * EPS_SMALL Then
               EgtSetMachiningParam(MCH_MP.FACEUSE, MCH_MIL_FU.ORTUP_FRONT)
               vtSide = Vector3d.Y_AX()
            ElseIf vtAdjN.y < -10 * EPS_SMALL Then
               EgtSetMachiningParam(MCH_MP.FACEUSE, MCH_MIL_FU.ORTUP_BACK)
               vtSide = -Vector3d.Y_AX()
            End If
         End If
         ' Calcolo elevazione
         Dim ptP1, ptP2 As Point3d
         If Not EgtSurfTmFacetOppositeSide(nSurfId, nFacetInd, vtSide, GDB_ID.ROOT, ptP1, ptP2) Then Return False
         Dim ptPM As Point3d = Point3d.Media(ptP1, ptP2)
         Dim vtElev As Vector3d = vtN ^ (vtSide ^ vtN)
         If Not vtElev.Normalize() Then Return False
         Dim vInters As New List(Of FlagPar)
         If Not EgtLineSurfTmInters(ptPM, vtElev, nSolidId, GDB_ID.ROOT, vInters) Then Return False
         If vInters.Count() = 0 OrElse vInters(vInters.Count() - 1).dPar <= EPS_SMALL Then
            If Not EgtLineSurfTmInters(ptPM, vtElev, nSurfId, GDB_ID.ROOT, vInters) Then Return False
         End If
         If vInters.Count() > 0 AndAlso vInters(vInters.Count() - 1).dPar > EPS_SMALL Then
            dElev = vInters(vInters.Count() - 1).dPar
         Else
            dElev = dMaxMat
         End If
         ' Calcolo distanze iniziale e finale
         Dim vtTg As Vector3d = ptP2 - ptP1
         If Not vtTg.Normalize() Then Return False
         If Not EgtLineSurfTmInters(ptP1, -vtTg, nSolidId, GDB_ID.ROOT, vInters) Then Return False
         If vInters.Count() > 0 AndAlso vInters(vInters.Count() - 1).dPar > EPS_SMALL Then
            dStartDist = vInters(vInters.Count() - 1).dPar
         Else
            dStartDist = 0
         End If
         If Not EgtLineSurfTmInters(ptP2, vtTg, nSolidId, GDB_ID.ROOT, vInters) Then Return False
         If vInters.Count() > 0 AndAlso vInters(vInters.Count() - 1).dPar > EPS_SMALL Then
            dEndDist = vInters(vInters.Count() - 1).dPar
         Else
            dEndDist = 0
         End If
      End If
      ' Imposto SCC
      EgtSetMachiningParam(MCH_MP.SOLCHOICETYPE, MCH_SCC.ADIR_NEAR)
      ' Imposto lato di correzione
      EgtSetMachiningParam(MCH_MP.WORKSIDE, If(bLeftSide, MCH_MIL_WS.LEFT, MCH_MIL_WS.RIGHT))
      ' Annullo affondamento
      EgtSetMachiningParam(MCH_MP.DEPTH, 0.0)
      ' Se elevazione superiore a massimo materiale, riduco opportunamento per non collidere
      If dElev > dMaxMat Then
         EgtSetMachiningParam(MCH_MP.OFFSR, (dElev - dMaxMat))
         dElev = dMaxMat
      End If
      ' Se richiesto, imposto step di lato
      EgtSetMachiningParam(MCH_MP.STEPTYPE, If(nStepType = MCH_SAW_ST.ONEWAY, MCH_MIL_ST.ONEWAY, MCH_MIL_ST.ZIGZAG))
      If dStep >= EPS_SMALL And dStep < dElev Then
         EgtSetMachiningParam(MCH_MP.STEP_, dStep)
         EgtSetMachiningParam(MCH_MP.USERNOTES, "SideElev=" & dElev.ToString() & ";")
      End If
      ' Recupero la distanza di sicurezza
      Dim dSafeZ As Double = m_MainWindow.m_CurrentMachine.dSafeZ()
      ' Imposto attacco e uscita
      Dim dTgAgg As Double = Math.Sqrt(dElev * (dTDiam - dElev))
      EgtSetMachiningParam(MCH_MP.LEADINTYPE, MCH_MIL_LI.LINEAR)
      If nLiType = MCH_SAW_LI.CENT Or nLiType = MCH_SAW_LI.STRICT Then
         EgtSetMachiningParam(MCH_MP.LIPERP, dElev + dSafeZ)
      Else
         EgtSetMachiningParam(MCH_MP.LITANG, dStartDist + dTgAgg + dSafeZ)
      End If
      EgtSetMachiningParam(MCH_MP.LEADOUTTYPE, MCH_MIL_LO.LINEAR)
      If nLoType = MCH_SAW_LO.CENT Or nLoType = MCH_SAW_LO.STRICT Then
         EgtSetMachiningParam(MCH_MP.LOPERP, dElev + dSafeZ)
      Else
         EgtSetMachiningParam(MCH_MP.LOTANG, dEndDist + dTgAgg + dSafeZ)
      End If
      ' Imposto speed e feed
      EgtSetMachiningParam(MCH_MP.SPEED, dSpeed)
      EgtSetMachiningParam(MCH_MP.FEED, dFeed)
      EgtSetMachiningParam(MCH_MP.STARTFEED, dStartFeed)
      EgtSetMachiningParam(MCH_MP.ENDFEED, dEndFeed)
      EgtSetMachiningParam(MCH_MP.TIPFEED, dTipFeed)
      ' Applico la lavorazione
      Return EgtApplyMachining(False)
   End Function

End Module
