Imports EgtUILib

Public Module SplitAuto

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

   Private m_dLastDT As Double = 0
   Public ReadOnly Property dLastDT As Double
      Get
         Return m_dLastDT
      End Get
   End Property

   '-----------------------------------------------------------------------------------------------
   Friend Class SplitMach
      Public m_nId As Integer
      Public m_vOthId As New List(Of Integer)
      Public m_nType As Integer
      Public m_dSideAng As Double
      Public m_sLay As String
      Public m_nEntId As Integer
      Public m_nNbrId As Integer
      Public m_nArrId As Integer
      Public m_nInterf As Integer
      Public m_bCanStartAll As Boolean
      Public m_bCanEndAll As Boolean
      Public m_bStartAll As Boolean
      Public m_bEndAll As Boolean
      Public m_bEnabled As Boolean
      Public m_bPause As Boolean
      Public m_bEnableInvert As Boolean
      Public m_bInvert As Boolean
      Public m_bIsLine As Boolean
      Public m_dPrevAng As Double
      Public m_dNextAng As Double
      Public m_dStartFreeLen As Double
      Public m_dEndFreeLen As Double
      Public m_vtDir As Vector3d
   End Class

   '-----------------------------------------------------------------------------------------------
   Friend Function CalculateSplitMachList(nCurrPhase As Integer, ByRef MachSplitList As List(Of SplitMach)) As Boolean
      ' Pulisco la lista delle lavorazioni
      MachSplitList.Clear()
      ' La riempio
      Dim nOperId As Integer = EgtGetFirstOperation()
      While nOperId <> GDB_ID.NULL
         ' verifico sia una lavorazione valida della fase corrente
         If IsValidMachining(nOperId) And EgtGetOperationPhase(nOperId) = nCurrPhase Then
            ' se appartiene ad un grezzo attivo la inserisco in lista
            If IsMachiningInActiveRaw(nOperId) Then
               Dim Mach As New SplitMach
               Mach.m_nEntId = GDB_ID.NULL
               ' identificativo
               Mach.m_nId = nOperId
               ' eventuali lavorazioni inglobate
               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 Mach.m_vOthId.Add(nId)
                  Next
               End If
               ' tipo
               Mach.m_nType = EgtGetOperationType(nOperId)
               ' layer di origine
               EgtGetInfo(nOperId, INFO_MCH_LAYER, Mach.m_sLay)
               ' se taglio con lama
               If Mach.m_nType = MCH_OY.SAWING Then
                  ' verifica interferenza
                  If Mach.m_sLay = NAME_OUTLOOP Then
                     EgtVerifyMachining(nOperId, Mach.m_nInterf)
                     For Each nId As Integer In Mach.m_vOthId
                        Dim nRes As Integer = FMI_TYPE.LI Or FMI_TYPE.RM Or FMI_TYPE.LO
                        EgtVerifyMachining(nId, nRes)
                        Mach.m_nInterf = Mach.m_nInterf Or nRes
                     Next
                  Else
                     Mach.m_nInterf = FMI_TYPE.NONE
                  End If
                  ' la imposto come lavorazione corrente
                  EgtSetCurrMachining(nOperId)
                  ' inversione
                  EgtGetMachiningParam(MCH_MP.INVERT, Mach.m_bInvert)
                  ' recupero l'angolo di fianco
                  EgtGetMachiningParam(MCH_MP.SIDEANGLE, Mach.m_dSideAng)
                  ' recupero allungamento iniziale e finale (negativi vicino ad angoli interni)
                  Dim dStartAddLen As Double = -10
                  EgtGetMachiningParam(MCH_MP.STARTADDLEN, dStartAddLen)
                  Dim dEndAddLen As Double = -10
                  EgtGetMachiningParam(MCH_MP.ENDADDLEN, dEndAddLen)
                  ' recupero tipo entità, angolo con entità precedente e successiva, lunghezze libere iniziale e finale
                  Mach.m_bIsLine = True
                  Mach.m_dPrevAng = 0
                  Mach.m_dNextAng = 0
                  Mach.m_dStartFreeLen = FREELEN_INF + 1
                  Mach.m_dEndFreeLen = FREELEN_INF + 1
                  Dim nEntId, nSub As Integer
                  If EgtGetMachiningGeometry( 0, nEntId, nSub) Then
                     If EgtGetType( nEntId) = GDB_TY.CRV_ARC OrElse EgtGetType( nEntId) = GDB_TY.CRV_COMPO Then Mach.m_bIsLine = False
                     EgtGetInfo( nEntId, If( Not Mach.m_bInvert, INFO_PREVANG, INFO_NEXTANG), Mach.m_dPrevAng)
                     EgtGetInfo( nEntId, If( Not Mach.m_bInvert, INFO_NEXTANG, INFO_PREVANG), Mach.m_dNextAng)
                     EgtGetInfo( nEntId, If( Not Mach.m_bInvert, INFO_START_FREELEN, INFO_END_FREELEN), Mach.m_dStartFreeLen)
                     EgtGetInfo( nEntId, If( Not Mach.m_bInvert, INFO_END_FREELEN, INFO_START_FREELEN), Mach.m_dEndFreeLen)
                     Mach.m_bEnableInvert = GetEnableInvert( nEntId)
                     EgtMidVector( nEntId, GDB_ID.ROOT, Mach.m_vtDir)
                     If Mach.m_bInvert Then Mach.m_vtDir = -Mach.m_vtDir
                     Mach.m_nEntId = nEntId
                  End If
                  ' verifico se trasformabile in un taglio di separazione (almeno da un lato)
                  If (dStartAddLen > -EPS_SMALL Or dEndAddLen > -EPS_SMALL) And
                     Mach.m_sLay = NAME_OUTLOOP And Mach.m_nInterf = FMI_TYPE.NONE Then
                     Dim nRes As Integer = EgtVerifyCutAsSplitting(nOperId)
                     Mach.m_bCanStartAll = (dStartAddLen > -EPS_SMALL And (nRes And CAR_RES.LI_OK) <> 0) And
                                           Mach.m_dStartFreeLen > FREELEN_INF And Mach.m_bIsLine
                     Mach.m_bCanEndAll = (dEndAddLen > -EPS_SMALL And (nRes And CAR_RES.LO_OK) <> 0) And
                                         Mach.m_dEndFreeLen > FREELEN_INF And Mach.m_bIsLine
                  End If
                  ' se trasformabile in taglio di separazione, verifico se lo è
                  If Mach.m_bCanStartAll Or Mach.m_bCanEndAll Then
                     EgtSetCurrMachining(nOperId)
                     Dim nLiType As Integer
                     EgtGetMachiningParam(MCH_MP.LEADINTYPE, nLiType)
                     Dim nLoType As Integer
                     EgtGetMachiningParam(MCH_MP.LEADOUTTYPE, nLoType)
                     Mach.m_bStartAll = (nLiType = MCH_SAW_LI.EXT_CENT Or nLiType = MCH_SAW_LI.EXT_OUT)
                     Mach.m_bEndAll = (nLoType = MCH_SAW_LO.EXT_CENT Or nLoType = MCH_SAW_LO.EXT_OUT)
                  Else
                     Mach.m_bStartAll = False
                     Mach.m_bEndAll = False
                  End If
               ' Waterjet
               ElseIf Mach.m_nType = MCH_OY.WATERJETTING Then
                  Mach.m_nInterf = FMI_TYPE.NONE
                  ' recupero l'angolo di fianco
                  EgtGetMachiningParam(MCH_MP.SIDEANGLE, Mach.m_dSideAng)
                  Mach.m_bCanStartAll = False
                  Mach.m_bCanEndAll = False
                  Mach.m_bStartAll = False
                  Mach.m_bEndAll = False
               ' Forature e fresature
               Else
                  Mach.m_nInterf = FMI_TYPE.NONE
                  Mach.m_dSideAng = 0
                  Mach.m_bCanStartAll = False
                  Mach.m_bCanEndAll = False
                  Mach.m_bStartAll = False
                  Mach.m_bEndAll = False
               End If
               ' abilitazione
               Mach.m_bEnabled = Not EgtExistsInfo(nOperId, INFO_MCH_USER_OFF)
               ' pausa
               Mach.m_bPause = GetPause(nOperId)
               ' inserisco in lista
               MachSplitList.Add(Mach)
            ' altrimenti la disattivo
            Else
               EgtSetOperationMode(nOperId, False)
            End If
         End If
         nOperId = EgtGetNextOperation(nOperId)
      End While
      Return True
   End Function

   '-----------------------------------------------------------------------------------------------
   ' calcolo il numero di tipi di lavorazioni
   Friend Sub CountMachiningType(MachSplit As SplitMach, ByRef nCountSawing As Integer, ByRef nCountWaterjetting As Integer, ByRef nCountOtherMachining As Integer)
      If MachSplit.m_nType = MCH_OY.SAWING Then
         nCountSawing += 1
      ElseIf MachSplit.m_nType = MCH_OY.WATERJETTING Then
         nCountWaterjetting += 1
      Else
         nCountOtherMachining += 1
      End If
   End Sub

   Friend Sub ColorMachining(MachSplit As SplitMach, Optional bReset As Boolean = False)
      EgtDisableModified()
      ' Assegno stato
      Dim bEnabled As Boolean = MachSplit.m_bEnabled
      Dim nInterf As Integer = If(bReset, FMI_TYPE.NONE, MachSplit.m_nInterf)
      ' Colore della lavorazione principale
      ColorSingleMachining(MachSplit.m_nId, MachSplit.m_sLay, MachSplit.m_dSideAng, bEnabled, nInterf)
      ' Colore delle lavorazioni inglobate
      For Each nId As Integer In MachSplit.m_vOthId
         ColorSingleMachining(nId, MachSplit.m_sLay, MachSplit.m_dSideAng, bEnabled, nInterf)
      Next
      EgtEnableModified()
   End Sub

   Private Sub ColorSingleMachining(nOperId As Integer, sLay As String, dSideAng As Double, bEnabled As Boolean, nInterf As Integer)
      ' Verifico se è un taglio da sopra o da sotto
      Dim bOnMach As Boolean = (sLay = NAME_ONPATH Or ( sLay = NAME_INLOOP AndAlso EgtExistsInfo( nOperId, INFO_FILOTOP)))
      Dim bDrip As Boolean = (sLay = NAME_DRIPCUT Or sLay = NAME_UNDERDRILL)
      ' Recupero il preview della lavorazione
      Dim nPvId As Integer = GDB_ID.NULL
      EgtGetInfo(EgtGetFirstNameInGroup(nOperId, NAME_PREVIEW), INFO_PV_ONPART_ID, nPvId)
      ' Cambio il colore 
      Dim nGrpId As Integer = EgtGetFirstGroupInGroup(nPvId)
      While nGrpId <> GDB_ID.NULL
         Dim vCutId As New List(Of Integer)
         Dim nId As Integer = EgtGetFirstNameInGroup(nGrpId, NAME_PV_CUT)
         While nId <> GDB_ID.NULL
            vCutId.Add(nId)
            nId = EgtGetNextName(nId, NAME_PV_CUT)
         End While
         Dim nPrcId As Integer = EgtGetFirstNameInGroup(nGrpId, NAME_PV_PRECUT)
         Dim nPocId As Integer = EgtGetFirstNameInGroup(nGrpId, NAME_PV_POSTCUT)
         Dim nDwnCutId As Integer = EgtGetFirstNameInGroup(nGrpId, NAME_PV_DOWN_CUT)
         Dim nDwnPrcId As Integer = EgtGetFirstNameInGroup(nGrpId, NAME_PV_DOWN_PRECUT)
         Dim nDwnPocId As Integer = EgtGetFirstNameInGroup(nGrpId, NAME_PV_DOWN_POSTCUT)
         If Not bEnabled Then
            For Each nId In vCutId
               EgtSetColor(nId, COL_MCH_DISABLED)
            Next
            EgtSetColor(nDwnCutId, COL_MCH_DISABLED)
            Dim bFreeStart As Boolean = (nInterf And FMI_TYPE.LI) <> FMI_TYPE.LI
            EgtSetColor(nPrcId, If(bFreeStart, COL_MCH_DISABLED, COL_MCH_DIS_INTERF))
            EgtSetColor(nDwnPrcId, If(bFreeStart, COL_MCH_DISABLED, COL_MCH_DIS_INTERF))
            Dim bFreeEnd As Boolean = (nInterf And FMI_TYPE.LO) <> FMI_TYPE.LO
            EgtSetColor(nPocId, If(bFreeEnd, COL_MCH_DISABLED, COL_MCH_DIS_INTERF))
            EgtSetColor(nDwnPocId, If(bFreeEnd, COL_MCH_DISABLED, COL_MCH_DIS_INTERF))
         Else
            Dim colCut As Color3d
            If bOnMach Then
               colCut = COL_MCH_ONCUT()
            ElseIf bDrip Then
               colCut = COL_MCH_DRIPCUT()
            ElseIf Math.Abs(dSideAng) > EPS_ANG_SMALL Then
               colCut = COL_MCH_CUT_ANG()
            Else
               colCut = COL_MCH_CUT()
            End If
            For Each nId In vCutId
               EgtSetColor(nId, colCut)
            Next
            EgtSetColor(nDwnCutId, colCut)
            Dim colStart As Color3d = COL_MCH_INTERF()
            If (nInterf And FMI_TYPE.LI) <> FMI_TYPE.LI Then
               If bOnMach Then
                  colStart = COL_MCH_ONFREE()
               ElseIf bDrip Then
                  colStart = COL_MCH_DRIPFREE()
               Else
                  colStart = COL_MCH_FREE()
               End If
            End If
            EgtSetColor(nPrcId, colStart)
            EgtSetColor(nDwnPrcId, colStart)
            Dim colEnd As Color3d = COL_MCH_INTERF()
            If (nInterf And FMI_TYPE.LO) <> FMI_TYPE.LO Then
               If bOnMach Then
                  colEnd = COL_MCH_ONFREE()
               ElseIf bDrip Then
                  colEnd = COL_MCH_DRIPFREE()
               Else
                  colEnd = COL_MCH_FREE()
               End If
            End If
            EgtSetColor(nPocId, colEnd)
            EgtSetColor(nDwnPocId, colEnd)
         End If
         nGrpId = EgtGetNextGroup(nGrpId)
      End While
   End Sub

   '-----------------------------------------------------------------------------------------------
   Friend Sub ShowOnePhaseMachiningPreview(nPhase As Integer)
      Dim bOldEnMod As Boolean = EgtGetEnableModified()
      EgtDisableModified()
      Dim nOpeId = EgtGetFirstOperation()
      While nOpeId <> GDB_ID.NULL
         If EgtGetOperationType(nOpeId) <> MCH_OY.DISP And
            (EgtGetOperationMode(nOpeId) OrElse EgtExistsInfo(nOpeId, INFO_MCH_USER_OFF) OrElse EgtExistsInfo(nOpeId, INFO_MCH_DUPLED)) Then
            Dim nStatus As Integer = If(EgtGetOperationPhase(nOpeId) = nPhase, GDB_ST.ON_, GDB_ST.OFF)
            ' Lavorazione principale
            Dim nPvId As Integer = GDB_ID.NULL
            EgtGetInfo(EgtGetFirstNameInGroup(nOpeId, NAME_PREVIEW), INFO_PV_ONPART_ID, nPvId)
            EgtSetStatus(nPvId, nStatus)
            ' Eventuali lavorazioni inglobate
            Dim sInfo As String = String.Empty
            If EgtGetInfo(nOpeId, INFO_MCH_OTHMID, sInfo) Then
               Dim sItems() As String = sInfo.Split(",".ToCharArray)
               For Each sId As String In sItems
                  Dim nId As Integer = GDB_ID.NULL
                  StringToInt(sId, nId)
                  Dim nPvId2 As Integer = GDB_ID.NULL
                  EgtGetInfo(EgtGetFirstNameInGroup(nId, NAME_PREVIEW), INFO_PV_ONPART_ID, nPvId2)
                  EgtSetStatus(nPvId2, nStatus)
               Next
            End If
         End If
         nOpeId = EgtGetNextOperation(nOpeId)
      End While
      If bOldEnMod Then EgtEnableModified()
   End Sub

   Friend Sub ShowAllPhasesMachiningPreview()
      Dim bOldEnMod As Boolean = EgtGetEnableModified()
      EgtDisableModified()
      Dim nOpeId = EgtGetFirstOperation()
      While nOpeId <> GDB_ID.NULL
         If EgtGetOperationType(nOpeId) <> MCH_OY.DISP And
            (EgtGetOperationMode(nOpeId) OrElse EgtExistsInfo(nOpeId, INFO_MCH_USER_OFF) OrElse EgtExistsInfo(nOpeId, INFO_MCH_DUPLED)) Then
            Dim nStatus As Integer = GDB_ST.ON_
            ' Lavorazione principale
            Dim nPvId As Integer = GDB_ID.NULL
            EgtGetInfo(EgtGetFirstNameInGroup(nOpeId, NAME_PREVIEW), INFO_PV_ONPART_ID, nPvId)
            EgtSetStatus(nPvId, nStatus)
            ' Eventuali lavorazioni inglobate
            Dim sInfo As String = String.Empty
            If EgtGetInfo(nOpeId, INFO_MCH_OTHMID, sInfo) Then
               Dim sItems() As String = sInfo.Split(",".ToCharArray)
               For Each sId As String In sItems
                  Dim nId As Integer = GDB_ID.NULL
                  StringToInt(sId, nId)
                  Dim nPvId2 As Integer = GDB_ID.NULL
                  EgtGetInfo(EgtGetFirstNameInGroup(nId, NAME_PREVIEW), INFO_PV_ONPART_ID, nPvId2)
                  EgtSetStatus(nPvId2, nStatus)
               Next
            End If
         End If
         nOpeId = EgtGetNextOperation(nOpeId)
      End While
      If bOldEnMod Then EgtEnableModified()
   End Sub

   '-----------------------------------------------------------------------------------------------
   Friend Function SplitRawParts(nPrevPhase As Integer, vCuts() As Integer,
                                 ByRef vNewRaws As List(Of Integer)) As Boolean
      ' Aggiorno preview di questi tagli lasciandoli nella lavorazione
      For Each nCut As Integer In vCuts
         UpdateMachiningPreview(nCut, False)
      Next
      ' Creo nuova fase
      Dim nNewPhase As Integer = EgtAddPhase()
      ' Origine della tavola
      Dim ptOri As Point3d
      EgtGetTableRef(1, ptOri)
      Dim vtOri As New Vector3d(ptOri.x, ptOri.y, ptOri.z)
      ' Eseguo eventuali spezzature dei grezzi e vi sposto i pezzi (i grezzi devono essere sempre copiati per Registrazione con rotazione)
      Dim nRawId As Integer = EgtGetFirstRawPart()
      While nRawId <> GDB_ID.NULL
         ' se il grezzo è presente nella fase precedente
         If EgtVerifyRawPartPhase(nRawId, nPrevPhase) Then
            ' Calcolo nuovi grezzi
            Dim nRaw1Id = EgtSplitFlatRawPartWithMachinings(nRawId, vCuts)
            ' Fisso posizione dei nuovi grezzi
            Dim nNewRawId = nRaw1Id
            While nNewRawId <> GDB_ID.NULL
               Dim ptMin, ptMax As Point3d
               EgtGetRawPartBBox(nNewRawId, ptMin, ptMax)
               EgtMoveToCornerRawPart(nNewRawId, ptMin - vtOri, MCH_CR.BL)
               nNewRawId = EgtGetNextRawPart(nNewRawId)
            End While
            ' Se almeno 2 grezzi da uno vecchio, li considero nuovi
            If EgtGetNextRawPart(nRaw1Id) <> GDB_ID.NULL Then
               nNewRawId = nRaw1Id
               While nNewRawId <> GDB_ID.NULL
                  vNewRaws.Add(nNewRawId)
                  nNewRawId = EgtGetNextRawPart(nNewRawId)
               End While
            End If
            ' Assegno ai nuovi grezzi eventuale texture del grezzo originale
            Dim nSolidId = EgtGetFirstNameInGroup(nRawId, NAME_RAW_SOLID)
            Dim nameTxr As String = String.Empty
            If EgtGetTextureName(nSolidId, nameTxr) Then
               Dim refTxr As New Frame3d
               EgtGetTextureFrame(nSolidId, GDB_ID.ROOT, refTxr)
               nNewRawId = nRaw1Id
               While nNewRawId <> GDB_ID.NULL
                  ' Carico la texture sul nuovo grezzo
                  Dim nNewSolidId = EgtGetFirstNameInGroup(nNewRawId, NAME_RAW_SOLID)
                  EgtSetTextureName(nNewSolidId, nameTxr)
                  ' Sistemo il riferimento della texture
                  EgtSetTextureFrame(nNewSolidId, refTxr, GDB_RT.GLOB)
                  ' Passo al grezzo successivo
                  nNewRawId = EgtGetNextRawPart(nNewRawId)
               End While
            End If
         End If
         ' passo al successivo grezzo
         nRawId = EgtGetNextRawPart(nRawId)
      End While
      ' Cancello preview dei tagli allungati dalla lavorazione
      For Each nCut As Integer In vCuts
         RemoveMachiningPreview(nCut)
      Next
      ' Sposto tutte le lavorazioni disabilitate e le eventuali inglobate nella nuova fase
      Dim nId = EgtGetFirstOperation()
      While nId <> GDB_ID.NULL
         Dim nNextId = EgtGetNextOperation(nId)
         If IsValidMachining(nId) And EgtGetOperationPhase(nId) = nNewPhase - 1 And EgtExistsInfo(nId, INFO_MCH_USER_OFF) Then
            ' sposto la lavorazione
            EgtChangeOperationPhase(nId, nNewPhase)
            ' sposto le inglobate
            Dim sInfo As String = String.Empty
            If EgtGetInfo(nId, INFO_MCH_OTHMID, sInfo) Then
               Dim sItems() As String = sInfo.Split(",".ToCharArray)
               For Each sId2 As String In sItems
                  Dim nId2 As Integer = 0
                  StringToInt(sId2, nId2)
                  If nId2 > 0 Then EgtChangeOperationPhase(nId2, nNewPhase)
               Next
            End If
         End If
         nId = nNextId
      End While
      Return True
   End Function

   '-----------------------------------------------------------------------------------------------
   Friend Function CalculateSplitAuto() As Boolean
      ' Fase iniziale
      EgtSetCurrPhase(1)
      ' Cancello tutte le lavorazioni
      EraseMachinings(GDB_ID.NULL)
      ' Reinserisco tutte le lavorazioni
      Dim nWarn As Integer = 0
      AddMachinings(GDB_ID.NULL, nWarn)
      If nWarn = 1 Then m_MainWindow.m_CurrentProjectPageUC.SetWarningMessage(EgtMsg(MSG_SPLITPAGEUC + 11)) ' Lama troppo grande per utilizzo ventosa
      ' Carico ventose
      LoadVacuumCups()
      ' Lancio calcolo separazione
      Dim bFinished As Boolean = False
      While CalculateOnePhaseSplitAuto(bFinished)
         If bFinished Then
            Exit While
         End If
      End While
      ' Se non finito con successo, verifico se necessario limitare lavorazioni
      If Not bFinished Then
         If Not TestMachiningCurrPhaseForStrict() Then
            m_MainWindow.m_CurrentProjectPageUC.SetWarningMessage(EgtMsg(90321))     'Ridotte alcune lavorazioni per evitare interferenze
         End If
      End If
      EgtSetCurrPhase(1)
      ' Scarico ventose
      RemoveVacuumCups()
      Return bFinished
   End Function

   '-----------------------------------------------------------------------------------------------
   Friend Function CalculateOnePhaseSplitAuto(ByRef bFinished As Boolean) As Boolean
      ' Faccio ordine automatico delle lavorazioni
      If Not SortAllMachinings() Then Return False
      m_MainWindow.m_CurrentProjectPageUC.SetOrderMachiningFlag()
      ' Recupero l'indice della fase corrente
      Dim nCurrPhase As Integer = EgtGetCurrPhase()
      ' Preparo la lista delle lavorazioni
      Dim MachSplitList As New List(Of SplitMach)
      If Not CalculateSplitMachList(nCurrPhase, MachSplitList) Then Return False
      ' Se non ci sono interferenze
      If Not FindInterferences(MachSplitList) Then
         ' Abilito tutte le lavorazioni della lista
         EnableAllMachinings(MachSplitList)
         ' Dichiaro conclusione ed esco
         bFinished = True
         Return True
      End If
      ' Disabilito tutte le lavorazioni della lista
      DisableAllMachinings(MachSplitList)
      ' Cerco il miglior taglio di separazione
      Dim nCutInd As Integer = FindBestSeparationCut(MachSplitList)
      If nCutInd < 0 Then Return False
      ' Eseguo il taglio
      If Not MakeSeparatingCut(MachSplitList(nCutInd).m_nId) Then Return False
      MachSplitList(nCutInd).m_bEnabled = True
      MachSplitList(nCutInd).m_bStartAll = True
      MachSplitList(nCutInd).m_bEndAll = True
      ColorMachining(MachSplitList(nCutInd))
      ' Spezzo i grezzi creando una nuova fase di lavoro
      Dim vCuts() As Integer = {MachSplitList(nCutInd).m_nId}
      Dim vNewRaws As New List(Of Integer)
      If SplitRawParts(nCurrPhase, vCuts, vNewRaws) Then
         ' Eseguo gli spostamenti dei grezzi
         If MoveRawParts(MachSplitList(nCutInd).m_nId, vNewRaws) Then
            While vNewRaws.Count() >= 4
               vNewRaws.RemoveAt(0)
               vNewRaws.RemoveAt(0)
               MoveRawParts(MachSplitList(nCutInd).m_nId, vNewRaws)
            End While
            bFinished = False
            Return True
         End If
      End If
      ' Ci sono stati errori dopo aver creato la nuova fase, ripristino la vecchia
      RemoveLastPhase()
      bFinished = False
      Return False
   End Function

   '-----------------------------------------------------------------------------------------------
   '-----------------------------------------------------------------------------------------------
   Private Function FindInterferences(ByRef MachSplitList As List(Of SplitMach)) As Boolean
      Dim bInterf As Boolean = False
      For Each MachSplit As SplitMach In MachSplitList
         If MachSplit.m_nInterf <> FMI_TYPE.NONE Then
            bInterf = True
            Exit For
         End If
      Next
      Return bInterf
   End Function

   Private Function EnableAllMachinings(ByRef MachSplitList As List(Of SplitMach)) As Boolean
      For nI As Integer = 0 To MachSplitList.Count() - 1
         If Not MachSplitList(nI).m_bEnabled Then
            MachSplitList(nI).m_bEnabled = True
            EgtSetOperationMode(MachSplitList(nI).m_nId, True)
            EgtRemoveInfo(MachSplitList(nI).m_nId, INFO_MCH_USER_OFF)
            ColorMachining(MachSplitList(nI))
         End If
      Next
      Return True
   End Function

   Private Function DisableAllMachinings(ByRef MachSplitList As List(Of SplitMach)) As Boolean
      For nI As Integer = 0 To MachSplitList.Count() - 1
         If MachSplitList(nI).m_bEnabled Then
            MachSplitList(nI).m_bEnabled = False
            EgtSetOperationMode(MachSplitList(nI).m_nId, False)
            EgtSetInfo(MachSplitList(nI).m_nId, INFO_MCH_USER_OFF, True)
            ColorMachining(MachSplitList(nI))
         End If
      Next
      Return True
   End Function

   Private Function FindBestSeparationCut(MachSplitList As List(Of SplitMach)) As Integer
      Dim nInd As Integer = -1
      Dim nMaxInterf As Integer = 0
      m_dLastDT = 0
      For nI As Integer = 0 To MachSplitList.Count() - 1
         Dim MachSplit As SplitMach = MachSplitList(nI)
         ' Se non allungabile ad entrambi gli estremi, vado oltre
         If Not MachSplit.m_bCanStartAll Or Not MachSplit.m_bCanEndAll Then Continue For
         ' Se ci sono lavorazioni componenti, calcolo preview completo in lavorazione
         If MachSplit.m_vOthId.Count() > 0 Then
            UpdateMachiningPreview(MachSplit.m_nId, False)
         End If
         ' Contatore interferenze altri tagli con taglio corrente
         Dim nCurrInterf As Integer = 0
         ' Lunghezza baffi altri tagli che interferiscono su taglio corrente
         Dim dCurrInterfLen As Double = 0
         ' Determino quanti tagli con interferenza interseca
         For Each MachSplit2 As SplitMach In MachSplitList
            ' Se coincide con il precedente, vado oltre
            If MachSplit2.m_nId = MachSplit.m_nId Then Continue For
            ' Se non interferisce, vado oltre
            If MachSplit2.m_nInterf = FMI_TYPE.NONE Then Continue For
            ' Se ci sono lavorazioni componenti, calcolo preview completo in lavorazione
            If MachSplit2.m_vOthId.Count() > 0 Then
               UpdateMachiningPreview(MachSplit2.m_nId, False)
            End If
            ' Eseguo verifica tra le lavorazioni
            Dim bInterf As Boolean = False
            If GetInterferenceWithOtherCut(MachSplit.m_nId, MachSplit2.m_nId, MachSplit2.m_nInterf) Then
               bInterf = True
               ' Recupero lunghezza baffo secondo taglio
               Dim nPvId As Integer = GDB_ID.NULL
               EgtGetInfo(EgtGetFirstNameInGroup(MachSplit2.m_nId, NAME_PREVIEW), INFO_PV_ONPART_ID, nPvId)
               Dim dDT As Double
               If EgtGetInfo(EgtGetFirstGroupInGroup(nPvId), "DT", dDT) And dDT > dCurrInterfLen Then
                  dCurrInterfLen = dDT
               End If
            End If
            If bInterf Then nCurrInterf += 1
            ' Rimozione eventuale preview completo in lavorazione
            RemoveMachiningPreview(MachSplit2.m_nId)
         Next
         ' Verifico se taglio corrente è nuovo campione
         If nCurrInterf > nMaxInterf Then
            nMaxInterf = nCurrInterf
            nInd = nI
            m_dLastDT = dCurrInterfLen
         End If
         ' Rimozione eventuale preview completo in lavorazione
         RemoveMachiningPreview(MachSplit.m_nId)
      Next
      Return nInd
   End Function

   Private Function GetInterferenceWithOtherCut(nId As Integer, nId2 As Integer, nInterf2 As Integer) As Boolean
      ' Se il secondo non ha interferenze, esco subito
      If nInterf2 = FMI_TYPE.NONE Then Return False
      ' Regione di taglio ridotta del primo
      Dim nPvId As Integer = EgtGetFirstNameInGroup(nId, NAME_PREVIEW)
      If EgtGetGroupObjs(nPvId) = 0 Then EgtGetInfo(nPvId, INFO_PV_ONPART_ID, nPvId)
      Dim nRCutId As Integer = EgtGetFirstNameInGroup(EgtGetFirstGroupInGroup(nPvId), NAME_PV_RCUT)
      ' Se il secondo ha l'attacco che interferisce
      If (nInterf2 And FMI_TYPE.LI) <> 0 Then
         ' Recupero regione dell'attacco
         Dim nPv2Id As Integer = EgtGetFirstNameInGroup(nId2, NAME_PREVIEW)
         If EgtGetGroupObjs(nPv2Id) = 0 Then EgtGetInfo(nPv2Id, INFO_PV_ONPART_ID, nPv2Id)
         Dim nRLiCut2Id As Integer = EgtGetFirstNameInGroup(EgtGetFirstGroupInGroup(nPv2Id), NAME_PV_RLICUT)
         ' Verifico se questa regione interferisce con quella del taglio di riferimento
         If EgtSurfFrChunkSimpleClassify(nRCutId, 0, nRLiCut2Id, 0, 20 * EPS_SMALL) <> REGC.OUT Then Return True
      End If
      ' Se il secondo ha l'uscita che interferisce
      If (nInterf2 And FMI_TYPE.LO) <> 0 Then
         ' Recupero Id della regione dell'uscita
         Dim nPv2Id As Integer = EgtGetFirstNameInGroup(nId2, NAME_PREVIEW)
         If EgtGetGroupObjs(nPv2Id) = 0 Then EgtGetInfo(nPv2Id, INFO_PV_ONPART_ID, nPv2Id)
         Dim nRLoCut2Id As Integer = EgtGetFirstNameInGroup(EgtGetFirstGroupInGroup(nPv2Id), NAME_PV_RLOCUT)
         ' Verifico se questa regione interferisce con quella del taglio di riferimento
         If EgtSurfFrChunkSimpleClassify(nRCutId, 0, nRLoCut2Id, 0, 20 * EPS_SMALL) <> REGC.OUT Then Return True
      End If
      Return False
   End Function

   Private Function MakeSeparatingCut(nCutId As Integer) As Boolean
      EgtSetCurrMachining(nCutId)
      Dim nLiPrev As Integer
      EgtGetMachiningParam(MCH_MP.LEADINTYPE, nLiPrev)
      Dim nLoPrev As Integer
      EgtGetMachiningParam(MCH_MP.LEADOUTTYPE, nLoPrev)
      ' allungo
      If nLiPrev = MCH_SAW_LI.OUT Then
         EgtSetMachiningParam(MCH_MP.LEADINTYPE, MCH_SAW_LI.EXT_OUT)
      Else
         EgtSetMachiningParam(MCH_MP.LEADINTYPE, MCH_SAW_LI.EXT_CENT)
      End If
      If nLoPrev = MCH_SAW_LO.OUT Then
         EgtSetMachiningParam(MCH_MP.LEADOUTTYPE, MCH_SAW_LO.EXT_OUT)
      Else
         EgtSetMachiningParam(MCH_MP.LEADOUTTYPE, MCH_SAW_LO.EXT_CENT)
      End If
      UpdateMachiningPreview(nCutId, True)
      EgtSetOperationMode(nCutId, True)
      EgtRemoveInfo(nCutId, INFO_MCH_USER_OFF)
      Return True
   End Function

   Private Function MoveRawParts(nCutId As Integer, vNewRaws As List(Of Integer)) As Boolean
      ' Almeno 2 nuovi grezzi (dovrebbero essere solo 2)
      If vNewRaws.Count() < 2 Then Return False
      ' Privilegio il grezzo più piccolo (lo porto in seconda posizione per essere mosso per primo)
      If GetSmallerRaw(vNewRaws(0), vNewRaws(1)) = 1 Then
         Dim nTmp As Integer = vNewRaws(0)
         vNewRaws(0) = vNewRaws(1)
         vNewRaws(1) = nTmp
      End If
      ' Centri dei primi 2 grezzi
      Dim ptCen0 As Point3d
      If Not EgtGetRawPartCenter(vNewRaws(0), ptCen0) Then Return False
      Dim ptCen1 As Point3d
      If Not EgtGetRawPartCenter(vNewRaws(1), ptCen1) Then Return False
      ' Direzione del taglio
      EgtSetCurrMachining(nCutId)
      Dim nEntId, nSub As Integer
      If Not EgtGetMachiningGeometry(0, nEntId, nSub) Then Return False
      Dim vtCutDir As Vector3d
      EgtStartVector(nEntId, GDB_ID.ROOT, vtCutDir)
      ' Distanza minima di spostamento
      Dim dExtraL As Double = 0
      EgtMdbGetGeneralParam(MCH_GP.EXTRALONCUTREG, dExtraL)
      Dim dMinMove As Double = m_dLastDT + dExtraL + 1
      ' Decido cosa muovere
      Dim nDispId As Integer = EgtGetPhaseDisposition(EgtGetCurrPhase())
      Dim dDeltaX = ptCen1.x - ptCen0.x
      Dim dDeltaY = ptCen1.y - ptCen0.y
      If Math.Abs(dDeltaX) < Math.Abs(dDeltaY) Then
         Dim vtMoveY As New Vector3d(0, dMinMove / Math.Abs(vtCutDir.x), 0)
         If dDeltaY < 0 Then vtMoveY = -vtMoveY
         If Not ExecMove(nDispId, vNewRaws, vtMoveY, dMinMove) Then
            If Math.Abs(dDeltaX) > 0.2 Then
               Dim vtMoveX As New Vector3d(dMinMove / Math.Abs(vtCutDir.y), 0, 0)
               If dDeltaX < 0 Then vtMoveX = -vtMoveX
               If Not ExecMove(nDispId, vNewRaws, vtMoveX, dMinMove) Then
                  Return False
               End If
            Else
               Return False
            End If
         End If
      Else
         Dim vtMoveX As New Vector3d(dMinMove / Math.Abs(vtCutDir.y), 0, 0)
         If dDeltaX < 0 Then vtMoveX = -vtMoveX
         If Not ExecMove(nDispId, vNewRaws, vtMoveX, dMinMove) Then
            If Math.Abs(dDeltaY) > 0.2 Then
               Dim vtMoveY As New Vector3d(0, dMinMove / Math.Abs(vtCutDir.x), 0)
               If dDeltaY < 0 Then vtMoveY = -vtMoveY
               If Not ExecMove(nDispId, vNewRaws, vtMoveY, dMinMove) Then
                  Return False
               End If
            Else
               Return False
            End If
         End If
      End If
      Return True
   End Function

   Private Function TestMachiningCurrPhaseForStrict() As Boolean
      ' Recupero l'indice della fase corrente
      Dim nCurrPhase As Integer = EgtGetCurrPhase()
      ' Preparo la lista delle lavorazioni
      Dim MachSplitList As New List(Of SplitMach)
      If Not CalculateSplitMachList(nCurrPhase, MachSplitList) Then Return False
      ' Affondamento ridotto
      Dim dReducedDepth As Double = GetPrivateProfileDouble(S_MACH_NEST, K_MACH_REDUCEDDEPTH, 1, m_MainWindow.GetMachIniFile())
      ' Restringo o rialzo lavorazioni abilitate ma con interferenza
      Dim bModified As Boolean = False
      For Each Mach As SplitMach In MachSplitList
         If Mach.m_bEnabled And Mach.m_nInterf <> FMI_TYPE.NONE Then
            If AdjustMachining(Mach.m_nId, Mach.m_nInterf, dReducedDepth) Then
               bModified = True
            End If
         End If
      Next
      Return bModified
   End Function

   Private Function GetSmallerRaw(nRaw1Id As Integer, nRaw2Id As Integer) As Integer
      ' Area del primo grezzo
      Dim nRc1Id As Integer = EgtGetFirstNameInGroup(nRaw1Id, NAME_RAW_OUTLINE)
      Dim dArea1 As Double = 0
      If Not EgtCurveAreaXY(nRc1Id, dArea1) Then Return 0
      ' Area del secondo grezzo
      Dim nRc2Id As Integer = EgtGetFirstNameInGroup(nRaw2Id, NAME_RAW_OUTLINE)
      Dim dArea2 As Double = 0
      If Not EgtCurveAreaXY(nRc2Id, dArea2) Then Return 0
      ' Confronto le aree
      If dArea1 < dArea2 Then
         Return 1
      Else
         Return 2
      End If

   End Function

   Private Function ExecMove(nDispId As Integer, vNewRaws As List(Of Integer),
                             vtMove As Vector3d, dMinMove As Double) As Boolean
      Dim vtMove2 As Vector3d = -vtMove
      Dim rmData As New RawMoveData
      If PutVacuumCupsOnRaw(vNewRaws(1), rmData) AndAlso
                        SafeMoveRawPart(vNewRaws(1), vtMove, dMinMove) Then
         rmData.m_vtRawMove = vtMove
         SaveOneMoveInfoInDisposition(nDispId, rmData)
         Return True
      ElseIf PutVacuumCupsOnRaw(vNewRaws(0), rmData) AndAlso
                        SafeMoveRawPart(vNewRaws(0), vtMove2, dMinMove) Then
         rmData.m_vtRawMove = vtMove2
         SaveOneMoveInfoInDisposition(nDispId, rmData)
         Return True
      Else
         Return False
      End If
   End Function

   Private Function SafeMoveRawPart(nRawId As Integer, ByRef vtMove As Vector3d, dMindist As Double) As Boolean
      ' Spostamento originale
      Dim vtOriMove As New Vector3d( vtMove)
      ' Livello di movimento
      Dim nMoveLevel As Integer = GetPrivateProfileInt( S_SPLIT, K_MOVE_LEV, 5, m_MainWindow.GetIniFile())
      Dim nMove As Integer = 1
      ' Se esce dalla tavola, movimento già annullato ed esco con errore
      If Not EgtMoveRawPart(nRawId, vtOriMove) Then Return False
      ' Se interferisce con altri grezzi, annullo movimento ed esco con errore
      If Not VerifyRawWithOtherRaws(nRawId, dMindist) Then
         EgtMoveRawPart(nRawId, -vtOriMove)
         Return False
      End If
      If nMoveLevel < 2 Then Return True
      ' Provo ad aggiungere un altro movimento
      If EgtMoveRawPart(nRawId, vtOriMove) Then
         If VerifyRawWithOtherRaws(nRawId, dMindist) Then
            vtMove += vtOriMove
            nMove += 1
            If nMoveLevel = nMove Then Return True
         Else
            EgtMoveRawPart(nRawId, -vtOriMove)
         End If
      End If
      ' Provo ad aggiungere un altro movimento
      If EgtMoveRawPart(nRawId, vtOriMove) Then
         If VerifyRawWithOtherRaws(nRawId, dMindist) Then
            vtMove += vtOriMove
            nMove += 1
            If nMoveLevel = nMove Then Return True
         Else
            EgtMoveRawPart(nRawId, -vtOriMove)
         End If
      End If
      ' Provo ad aggiungere un movimento dimezzato
      If EgtMoveRawPart(nRawId, 0.5 * vtOriMove) Then
         If VerifyRawWithOtherRaws(nRawId, dMindist) Then
            vtMove += 0.5 * vtOriMove
            nMove += 1
            If nMoveLevel = nMove Then return True
         Else
            EgtMoveRawPart(nRawId, -0.5 * vtOriMove)
         End If
      End If
      ' Provo ad aggiungere un movimento 1/4
      If EgtMoveRawPart(nRawId, 0.25 * vtOriMove) Then
         If VerifyRawWithOtherRaws(nRawId, dMindist) Then
            vtMove += 0.25 * vtOriMove
         Else
            EgtMoveRawPart(nRawId, -0.25 * vtOriMove)
         End If
      End If
      Return True
   End Function

   Private Function VerifyRawWithOtherRaws(nRawId As Integer, dMindist As Double) As Boolean
      ' Contorno del grezzo in esame
      Dim nRcId As Integer = EgtGetFirstNameInGroup(nRawId, NAME_RAW_OUTLINE)
      If nRcId = GDB_ID.NULL Then Return False
      ' Fase corrente
      Dim nCurrPhase As Integer = EgtGetCurrPhase()
      ' Recupero elenco dei contorni degli altri grezzi della fase indicata
      Dim OthRawList As New List(Of Integer)
      Dim nOthId As Integer = EgtGetFirstRawPart()
      While nOthId <> GDB_ID.NULL
         If EgtVerifyRawPartPhase(nOthId, nCurrPhase) Then
            If nOthId <> nRawId Then
               Dim nOthRcId As Integer = EgtGetFirstNameInGroup(nOthId, NAME_RAW_OUTLINE)
               If nOthRcId <> GDB_ID.NULL Then OthRawList.Add(nOthRcId)
            End If
         End If
         nOthId = EgtGetNextRawPart(nOthId)
      End While
      ' Box del grezzo in esame
      Dim b3Raw As New BBox3d
      EgtGetBBoxGlob(nRcId, GDB_BB.STANDARD, b3Raw)
      b3Raw.Expand(dMindist)
      ' Creo la curva offsettata della minima distanza (considero solo la prima, ovvero la più lunga)
      Dim nCount As Integer = 0
      Dim nOffsId = EgtOffsetCurveAdv(nRcId, dMindist, OFF_TYPE.FILLET, nCount)
      ' Verifico
      Dim bInterf As Boolean = False
      For Each nId As Integer In OthRawList
         Dim b3OthRaw As New BBox3d
         EgtGetBBoxGlob(nId, GDB_BB.STANDARD, b3OthRaw)
         ' Se i box interferiscono
         If b3Raw.OverlapsXY(b3OthRaw) Then
            ' Verifico i contorni esterni
            If EgtClosedCurveClassify(nOffsId, nId) <> CCREGC.OUT Then
               bInterf = True
               Exit For
            End If
         End If
      Next
      ' Cancello curve offset
      For i As Integer = 0 To nCount - 1
         EgtErase(nOffsId + i)
      Next
      Return (Not bInterf)
   End Function

   Public Function MaxCuttingMustache(dMustache As Double) As Double
      Dim MachSplitList As New List(Of SplitMach)
      ' Recupero l'indice della fase corrente
      Dim nCurrPhase As Integer = EgtGetCurrPhase()
      ' se non è stata creata nessuna lista allora restituisco il valore di Default
      If Not CalculateSplitMachList(nCurrPhase, MachSplitList) Then Return dMustache
      Dim NewMustache As Double = 0
      Dim ItemMachSplit As SplitMach
      For Each ItemMachSplit In MachSplitList
         ' Recupero lunghezza baffo secondo taglio
         Dim nPvId As Integer = GDB_ID.NULL
         EgtGetInfo(EgtGetFirstNameInGroup(ItemMachSplit.m_nId, NAME_PREVIEW), INFO_PV_ONPART_ID, nPvId)
         Dim dDT As Double
         If EgtGetInfo(EgtGetFirstGroupInGroup(nPvId), "DT", dDT) Then
            If NewMustache < dDT Then NewMustache = dDT
         End If
      Next
      Dim dExtraL As Double = 0
      EgtMdbGetGeneralParam(MCH_GP.EXTRALONCUTREG, dExtraL)
      ' se esiste il valore di un baffo allora sovrascrivo il valore di default
      If NewMustache > 0 Then
         dMustache = Math.Ceiling(NewMustache)
      End If
      Return dMustache + dExtraL
   End Function

End Module