Imports System.IO
Imports System.Windows.Interop
Imports System.Collections.ObjectModel
Imports System.Runtime.InteropServices
Imports EgtUILib
Imports EgtWPFLib

Public Class VeinMatchingWindow

   ' Riferimento alla MainWindow
   Private m_MainWindow As MainWindow = DirectCast(Application.Current.MainWindow, MainWindow)
   ' Dichiarazione Scene
   Friend WithEvents VeinMatchingScene As New Scene
   Private VeinMatchingSceneHost As New System.Windows.Forms.Integration.WindowsFormsHost
   ' Gestione finestra
   Private m_bFirst As Boolean = True
   Private m_bPositioned As Boolean = False
   ' Selezione e modifica
   Private m_nIdToSel As Integer = GDB_ID.NULL
   Private m_nIdToDesel As Integer = GDB_ID.NULL

   Private Sub Window_Initialized(sender As Object, e As EventArgs)
      ' Assegnazione scena all'host e posizionamento nella PlacePageGrid
      VeinMatchingSceneHost.Child = VeinMatchingScene
      VeinMatchingSceneHost.SetValue(Grid.ColumnProperty, 1)
      Me.VeinMatchingGrid.Children.Add(VeinMatchingSceneHost)
      ' Per non farla visualizzare alla creazione
      Me.Left = 32000
      ' Assegno messaggi
      NewBtn.Content = EgtMsg(MSG_CADCUTPAGEUC + 3)
      ExportBtn.Content = EgtMsg(MSG_CADCUTPAGEUC + 10)
   End Sub

   Private Sub Window_Loaded(sender As Object, e As RoutedEventArgs) Handles Me.Loaded
      If m_bFirst Then
         ' Imposto finestra senza SystemMenu
         Dim hwnd As IntPtr = New WindowInteropHelper(Me).Handle
         SetWindowLong(hwnd, GWL_STYLE, GetWindowLong(hwnd, GWL_STYLE) And Not WS_SYSMENU)
         ' imposto colore di default
         Dim DefColor As New Color3d(0, 0, 0)
         GetPrivateProfileColor(S_GEOMDB, K_DEFAULTCOLOR, DefColor, m_MainWindow.GetIniFile())
         VeinMatchingScene.SetDefaultMaterial(DefColor)
         ' imposto colori sfondo
         VeinMatchingScene.SetViewBackground(GetBackTopColor(), GetBackBottomColor())
         ' imposto colore di evidenziazione
         Dim MarkColor As New Color3d(255, 255, 0)
         GetPrivateProfileColor(S_SCENE, K_MARK, MarkColor, m_MainWindow.GetIniFile())
         VeinMatchingScene.SetMarkMaterial(MarkColor)
         ' imposto colore per superfici selezionate
         Dim SelSurfColor As New Color3d(255, 255, 192)
         GetPrivateProfileColor(S_SCENE, K_SELSURF, SelSurfColor, m_MainWindow.GetIniFile())
         VeinMatchingScene.SetSelSurfMaterial(SelSurfColor)
         ' imposto tipo e colore del rettangolo di zoom
         Dim bOutline As Boolean = True
         Dim ZwColor As New Color3d(0, 0, 0)
         GetPrivateProfileZoomWin(S_SCENE, K_ZOOMWIN, bOutline, ZwColor, m_MainWindow.GetIniFile())
         VeinMatchingScene.SetZoomWinAttribs(bOutline, ZwColor)
         ' imposto colore della linea di distanza
         Dim DstLnColor As New Color3d(255, 0, 0)
         GetPrivateProfileColor(S_SCENE, K_DISTLINE, DstLnColor, m_MainWindow.GetIniFile())
         VeinMatchingScene.SetDistLineMaterial(DstLnColor)
         ' imposto parametri OpenGL
         Dim nDriver As Integer = GetPrivateProfileInt(S_OPENGL, K_DRIVER, 3, m_MainWindow.GetIniFile())
         Dim b2Buff As Boolean = (GetPrivateProfileInt(S_OPENGL, K_DOUBLEBUFFER, 1, m_MainWindow.GetIniFile()) <> 0)
         Dim nColorBits As Integer = GetPrivateProfileInt(S_OPENGL, K_COLORBITS, 32, m_MainWindow.GetIniFile())
         Dim nDepthBits As Integer = GetPrivateProfileInt(S_OPENGL, K_DEPTHBITS, 32, m_MainWindow.GetIniFile())
         VeinMatchingScene.SetViewAttributes(nDriver, b2Buff, nColorBits, nDepthBits)
         ' inizializzo la scena (DB geometrico + visualizzazione) e verifico presenza chiave
         If Not VeinMatchingScene.Init() Then
            m_MainWindow.m_CadCutPageUC.m_ProjectMgr.VeinMatchingBtn.IsChecked = False
            Me.Close()
         End If
         ' dimensione lineare max in pixel delle textures
         Dim nTxrMaxLinPix As Integer = GetPrivateProfileInt(S_SCENE, K_TEXMAXLINPIX, 4096, m_MainWindow.GetIniFile())
         EgtSetTextureMaxLinPixels(nTxrMaxLinPix)
         m_bFirst = False
      End If
      ' inibisco selezione diretta da Scene
      VeinMatchingScene.SetStatusNull()
   End Sub

   Private Sub Window_Closed(sender As Object, e As EventArgs) Handles Me.Closed
      ' Salvo posizione Window (se posizionata e non minimizzata)
      If m_bPositioned And Me.WindowState <> WindowState.Minimized Then
         Dim nFlag As Integer = If(Me.WindowState = WindowState.Maximized, 1, 0)
         WritePrivateProfileWinPos(S_VEINMATCHING, K_VEINMA_PLACE, nFlag, CInt(Me.Left), CInt(Me.Top), CInt(Me.Width), CInt(Me.Height), m_MainWindow.GetIniFile())
      End If
   End Sub

   Friend Sub AdjustPosition()
      ' Se già pozizionata, esco subito
      If m_bPositioned Then Return
      ' Imposto posizione e dimensioni della MainWindow da INI
      Dim nFlag, nLeft, nTop, nWidth, nHeight As Integer
      If GetPrivateProfileWinPos(S_VEINMATCHING, K_VEINMA_PLACE, nFlag, nLeft, nTop, nWidth, nHeight, m_MainWindow.GetIniFile()) Then
         Dim PtTL = New System.Drawing.Point(nLeft, nTop)
         Dim s As System.Windows.Forms.Screen = System.Windows.Forms.Screen.FromPoint(PtTL)
         If s.Bounds.Contains(PtTL) Then
            Me.WindowStartupLocation = Windows.WindowStartupLocation.Manual
            Me.Top = nTop
            Me.Left = nLeft
            Me.Height = nHeight
            Me.Width = nWidth
            Me.WindowState = If(nFlag = 1, WindowState.Maximized, WindowState.Normal)
            m_bPositioned = True
            Return
         End If
      End If
      ' Imposto in posizione standard
      Me.WindowStartupLocation = Windows.WindowStartupLocation.Manual
      Me.Top = m_MainWindow.Top
      Me.Left = m_MainWindow.Left
      Me.Height = nHeight
      Me.Width = nWidth
      Me.WindowState = If(nFlag = 1, WindowState.Maximized, WindowState.Normal)
      m_bPositioned = True
   End Sub

   Private Sub OnMouseDownScene(sender As Object, e As Windows.Forms.MouseEventArgs) Handles VeinMatchingScene.OnMouseDownScene
      ' Si può selezionare solo con il tasto sinistro e se stato NULL
      If e.Button <> Windows.Forms.MouseButtons.Left Or Not VeinMatchingScene.IsStatusNull() Then Return
      ' Eseguo selezione
      EgtSetObjFilterForSelWin(True, True, True, True, True)
      Dim nSel As Integer
      EgtSelect(e.Location, Scene.DIM_SEL, Scene.DIM_SEL, nSel)
      ' Ricavo nome dell'entità selezionata e identificativo
      Dim nId As Integer = EgtGetFirstObjInSelWin()
      While nId <> GDB_ID.NULL
         ' Cerco l'identificativo del pezzo cui appartiene
         Dim nPartId As Integer = EgtGetParent(EgtGetParent(nId))
         If EgtIsPart(nPartId) Then
            Dim nStat As Integer = GDB_ST.ON_
            EgtGetStatus(nPartId, nStat)
            ' Se già selezionato o posizione oggetto incompatibile con flag posizione selezionati
            If nStat = GDB_ST.SEL Then
               ' Memorizzo Id da deselezionare
               m_nIdToDesel = nPartId
            Else
               ' Memorizzo Id da selezionare
               m_nIdToSel = nPartId
            End If
            EgtDraw()
            Exit While
         End If
         ' Passo al successivo
         nId = EgtGetNextObjInSelWin()
      End While
   End Sub

   Private Sub OnMouseUpScene(sender As Object, e As System.Windows.Forms.MouseEventArgs) Handles VeinMatchingScene.OnMouseUpScene
      ' Se selezione da eseguire
      If m_nIdToSel <> GDB_ID.NULL Then
         ' Eseguo la selezione in Nesting
         Dim bSelected As Boolean = False
         Dim nOriId As Integer = GDB_ID.NULL
         EgtGetInfo(m_nIdToSel, KEY_ORI_ID, nOriId)
         If EgtSetCurrentContext(m_MainWindow.m_CurrentProjectPageUC.CurrentProjectScene.GetCtx()) AndAlso EgtExistsObj(nOriId) Then
            If (m_MainWindow.m_CadCutPageUC.m_NestPage.SelectPart(nOriId, False)) Then
               bSelected = True
            Else
               ' "Attenzione"    "Pezzo non selezionabile in questa condizione"
               Dim Mbox As New EgtMsgBox(Me, 350, EgtMsgBox.WidthType.PIXEL, EgtMsg(91122), EgtMsg(91606), EgtMsgBox.Buttons.OK, EgtMsgBox.Icons.ESCLAMATION, 2)
            End If
         End If
         EgtSetCurrentContext(VeinMatchingScene.GetCtx())
         ' Se selezione riuscita, la eseguo anche in VME
         If bSelected Then EgtSelectObj(m_nIdToSel)
         ' Se deselezione da eseguire
      ElseIf m_nIdToDesel <> GDB_ID.NULL Then
         ' Eseguo la deselezione in Nesting
         Dim bDeselected As Boolean = False
         Dim nOriId As Integer = GDB_ID.NULL
         EgtGetInfo(m_nIdToDesel, KEY_ORI_ID, nOriId)
         If EgtSetCurrentContext(m_MainWindow.m_CurrentProjectPageUC.CurrentProjectScene.GetCtx()) AndAlso EgtExistsObj(nOriId) Then
            If (m_MainWindow.m_CadCutPageUC.m_NestPage.DeselectPart(nOriId, False)) Then
               bDeselected = True
            End If
         End If
         EgtSetCurrentContext(VeinMatchingScene.GetCtx())
         ' Se deselezione riuscita, la eseguo anche in VME
         If bDeselected Then EgtDeselectObj(m_nIdToDesel)
      End If
      ' Reset
      m_nIdToSel = GDB_ID.NULL
      m_nIdToDesel = GDB_ID.NULL
      EgtDraw()
   End Sub

   Private Sub NewBtn_Click(sender As Object, e As RoutedEventArgs) Handles NewBtn.Click
      VeinMatching.Clear()
   End Sub

   Private Sub ExportBtn_Click(sender As Object, e As RoutedEventArgs) Handles ExportBtn.Click
      VeinMatching.Export(m_MainWindow.GetVeinMatchingDir() & "\Image.jpg")
   End Sub

   Private Sub AssemblyBtn_Click(sender As Object, e As RoutedEventArgs) Handles AssemblyBtn.Click
      Dim ThicknessRaw As Double = m_MainWindow.m_CurrentProjectPageUC.m_dRawHeight
      VeinMatching.AssemblyParts(ThicknessRaw)
   End Sub

   Private Sub ImportCurrProjBtn_Click(sender As Object, e As RoutedEventArgs) Handles ImportCurrProjBtn.Click
      VeinMatching.LoadCurrPartFromProj()
   End Sub

End Class

Friend Module VeinMatching

   ' Riferimento alla MainWindow
   Private m_MainWindow As MainWindow = DirectCast(Application.Current.MainWindow, MainWindow)
   ' Contesto del VeinMatching
   Friend m_nVeinCtx As Integer = 0
   ' Nome fotografia
   Private m_nPhoto As Integer = 0
   ' Dimensioni immagine da esportare
   Private m_nImgWidth As Integer = 1600
   Private m_nImgHeight As Integer = 1200
   ' Lista delle alzatine
   Private m_ListAlzFront As New ObservableCollection(Of Aletta)

   ' Costanti
   Const REF_NAME As String = "Ref"
   Const KEY_ORI_REF As String = "OriRef"

   Friend Function SetRefOnAllParts(nCtx As Integer) As Boolean
      ' Si opera nel contesto indicato
      EgtSetCurrentContext(nCtx)
      Dim nId As Integer = EgtGetFirstPart()
      While nId <> GDB_ID.NULL
         ' Gruppo regione
         Dim nRegLayId As Integer = EgtGetFirstNameInGroup(nId, NAME_REGION)
         ' Entità superficie regione piatta
         Dim nRegId As Integer = EgtGetFirstInGroup(nRegLayId)
         While nRegId <> GDB_ID.NULL
            If EgtGetType(nRegId) = GDB_TY.SRF_FRGN Then
               Exit While
            End If
            nRegId = EgtGetNext(nRegId)
         End While
         ' Ne recupero il centroide
         Dim ptCen As Point3d
         EgtCentroid(nRegId, GDB_ID.ROOT, ptCen)
         ' Inserisco il riferimento
         Dim frRef As New Frame3d(ptCen)
         Dim nRefId As Integer = EgtCreateGeoFrame(nRegLayId, frRef, GDB_RT.GLOB)
         EgtSetName(nRefId, REF_NAME)
         ' salvo nelle info il riferimento originale
         EgtSetInfo(nRefId, KEY_ORI_REF, frRef)
         ' nascondo l'oggetto appena inserito
         EgtSetMode(nRefId, GDB_MD.HIDDEN)
         ' Passo al pezzo successivo
         nId = EgtGetNextPart(nId)
      End While
      Return True
   End Function

   Friend Function SetRefOnPart(nId As Integer) As Boolean
      ' Si opera nel contesto corrente (CurrentProjectScene.GetCtx())
      ' Verifico validità identificativo oggetto
      If nId = GDB_ID.NULL Then Return False
      ' Recupero gruppo regione
      Dim nRegLayId As Integer = EgtGetFirstNameInGroup(nId, NAME_REGION)
      ' Se c'è già il riferimento, esco
      If EgtGetFirstNameInGroup(nRegLayId, REF_NAME) <> GDB_ID.NULL Then Return True
      ' Entità superficie regione piatta
      Dim nRegId As Integer = EgtGetFirstInGroup(nRegLayId)
      While nRegId <> GDB_ID.NULL
         If EgtGetType(nRegId) = GDB_TY.SRF_FRGN Then
               Exit While
         End If
         nRegId = EgtGetNext(nRegId)
      End While
      ' Ne recupero il centroide
      Dim ptCen As Point3d
      EgtCentroid(nRegId, GDB_ID.ROOT, ptCen)
      ' Inserisco il riferimento
      Dim frRef As New Frame3d(ptCen)
      Dim nRefId As Integer = EgtCreateGeoFrame(nRegLayId, frRef, GDB_RT.GLOB)
      EgtSetName(nRefId, REF_NAME)
      ' salvo nelle info il riferimento originale
      EgtSetInfo(nRefId, KEY_ORI_REF, frRef)
      ' nascondo l'oggetto appena inserito
      EgtSetMode(nRefId, GDB_MD.HIDDEN)
      Return True
   End Function

   ' ------------------- FUNZIONI PER GESTIONE ALZATINE E FRONTALINI -------------------
   Friend Function CreateListAlzAndFront() As Boolean
      m_ListAlzFront.Clear()
      EgtSetCurrentContext(m_nVeinCtx)
      Dim nId As Integer = EgtGetFirstPart()
      While nId <> GDB_ID.NULL
         ' verifico che il pezzo sia una alzatina
         Dim sInfoName As String = String.Empty
         EgtGetInfo(nId, "CMP", sInfoName)
         If sInfoName = "AlzFront" Then
            Dim AlzFront As New Aletta(nId)
            m_ListAlzFront.Add(AlzFront)
         End If
         ' Passo al pezzo successivo
         nId = EgtGetNextPart(nId)
      End While
      Return True
   End Function

   Friend Function LinkReferencesOnAlette() As Boolean
      Dim nId As Integer = EgtGetFirstPart()
      While nId <> GDB_ID.NULL
         ' escludo dalla ricerca le alette
         Dim sCMP As String = String.Empty
         EgtGetInfo(nId, "CMP", sCMP)
         If sCMP = "AlzFront" Then
            ' Passo al pezzo successivo
            nId = EgtGetNextPart(nId)
            Continue While
         End If
         ' Recupero gruppo regione
         Dim nOutLoopLayId As Integer = EgtGetFirstNameInGroup(nId, NAME_OUTLOOP)
         ' Entità lato
         Dim nSideId As Integer = EgtGetFirstInGroup(nOutLoopLayId)
         While nSideId <> GDB_ID.NULL
            Dim sInfoGUID As String = String.Empty
            EgtGetInfo(nSideId, "RefAF", sInfoGUID)
            If Not String.IsNullOrEmpty(sInfoGUID) Then
               Dim Item As Aletta
               For Each Item In m_ListAlzFront
                  If Item.RefGUID = sInfoGUID Then
                     Item.IdSideRef = nSideId
                  End If
               Next
               ' ricerco nella lista delle alette il suo 
            End If
            nSideId = EgtGetNext(nSideId)
         End While
         ' Passo al pezzo successivo
         nId = EgtGetNextPart(nId)
      End While
      Return True
   End Function

   ' ------------------- CARICO I PEZZI PRESENTI NEL PROGETTO CORRENTE -------------------
   ' carico tutti i pezzi del progetto corrente che sonon di tipo PCucina, PBagno, AlzFront
   Friend Function LoadCurrPartFromProj() As Boolean
      ' Recupero il contesto corrente
      Dim nCurrCtx = EgtGetCurrentContext()
      ' Imposto il contesto del progetto
      EgtSetCurrentContext(m_MainWindow.m_CurrentProjectPageUC.CurrentProjectScene.GetCtx())
      ' Disattivo il gruppo di lavoro corrente (cosi' tutti i pezzi vanno in parcheggio)
      EgtResetCurrMachGroup()
      ' Ciclo sui pezzi 
      Dim nId As Integer = EgtGetFirstPart()
      While nId <> GDB_ID.NULL
         Dim sCMP As String = String.Empty
         EgtGetInfo(nId, "CMP", sCMP)
         If sCMP.StartsWith("PCucina") Or sCMP.StartsWith("PBagno") Or sCMP.StartsWith("AlzFront") Then
            ' Aggiungo riferimento e lo inserisco in VeinMatching
            VeinMatching.SetRefOnPart(nId)
            VeinMatching.AddPartFromDraw(nId)
         End If
         ' Passo al pezzo successivo
         nId = EgtGetNextPart(nId)
      End While
      ' Imposto il contesto del progetto
      EgtSetCurrentContext(m_MainWindow.m_CurrentProjectPageUC.CurrentProjectScene.GetCtx())
      ' Riattivo il gruppo di lavoro
      EgtSetCurrMachGroup( EgtGetFirstMachGroup())
      ' Verifico quali pezzi sono nel grezzo, per dichiararlo al VM
      nId = EgtGetFirstPartInRawPart( CamAuto.GetCurrentRaw())
      While nId <> GDB_ID.NULL
         ' Dichiaro pezzo nel grezzo per VM
         VeinMatching.OnInsertPartInRaw( nId)
         ' Passo al pezzo successivo
         nId = EgtGetNextPartInRawPart(nId)
      End While
      ' Ripristino visualizzazione di eventuali pezzi in parcheggio
      ShowParkedParts()
      ' Ripristino il contesto corrente
      EgtSetCurrentContext( nCurrCtx)
      Return True
   End Function

   Friend Function Clear() As Boolean
      ' Verifico esista il contesto del VeinMatching
      If m_nVeinCtx = 0 Then Return True
      ' Imposto VeinMatching context
      Dim nCurrCtx = SetVeinContext()
      If nCurrCtx = 0 Then Return False
      ' Pulisco il DB
      EgtNewFile()
      EgtDraw()
      ' Reset contatore foto
      m_nPhoto = 0
      ' Se necessario, ripristino il contesto originale
      If nCurrCtx > 0 Then EgtSetCurrentContext(nCurrCtx)
      Return True
   End Function

   Friend Function AddPart(sPartFile As String, nPartId As Integer) As Boolean
      ' Verifico esista il contesto del VeinMatching
      If m_nVeinCtx = 0 Then Return True
      ' Imposto VeinMatching context
      Dim nCurrCtx = SetVeinContext()
      If nCurrCtx = 0 Then Return False
      ' Inserisco il pezzo
      EgtInsertFile(sPartFile)
      ' Ne recupero l'Id
      Dim nVeinId2 As Integer = EgtGetLastPart()
      ' Assegno Id originale
      EgtSetInfo(nVeinId2, KEY_ORI_ID, nPartId)
      ' Nascondo scritte, sono nel layer "Region"
      Dim nVeinRegId As Integer = EgtGetFirstNameInGroup(nVeinId2, NAME_REGION)
      Dim nCurrId As Integer = EgtGetFirstInGroup(nVeinRegId)
      While nCurrId <> GDB_ID.NULL
         If EgtGetType(nCurrId) = GDB_TY.EXT_TEXT Then EgtSetStatus(nCurrId, GDB_ST.OFF)
         nCurrId = EgtGetNext(nCurrId)
      End While
      ' Nascondo layer con valori angoli dei lati
      nCurrId = EgtGetFirstNameInGroup(nVeinId2, SIDE_ANGLE_LAYER)
      EgtSetStatus(nCurrId, GDB_ST.OFF)
      ' Nascondo layer preview lavorazioni
      nCurrId = EgtGetFirstNameInGroup(nVeinId2, NAME_PREVIEW)
      EgtSetStatus(nCurrId, GDB_ST.OFF)
      ' Se esiste OutLoop.orig OutLoop -> OutLoop.mach e OutLoop.orig -> OutLoop
      Dim nOutLoopOrig As Integer = EgtGetFirstNameInGroup( nVeinId2, NAME_OUTLOOP & ".orig")
      If nOutLoopOrig <> GDB_ID.NULL Then
         Dim nOutLoop As Integer = EgtGetFirstNameInGroup( nVeinId2, NAME_OUTLOOP)
         EgtSetName( nOutLoop, NAME_OUTLOOP & ".mach")
         EgtSetName( nOutLoopOrig, NAME_OUTLOOP)
      End If
      ' Se necessario, ripristino il contesto originale
      If nCurrCtx > 0 Then EgtSetCurrentContext(nCurrCtx)
      Return True
   End Function

   Friend Function AddParts(sPartFile As String, nFirstPartId As Integer) As Boolean
      ' Verifico esista il contesto del VeinMatching
      If m_nVeinCtx = 0 Then Return True
      ' Imposto VeinMatching context
      Dim nCurrCtx = SetVeinContext()
      If nCurrCtx = 0 Then Return False
      ' Inserisco i pezzi e recupero Id primo pezzo inserito
      Dim nFirstVeinId As Integer = EgtGetLastPart()
      EgtInsertFile(sPartFile)
      nFirstVeinId = If(nFirstVeinId <> GDB_ID.NULL, EgtGetNextPart(nFirstVeinId), EgtGetFirstPart())
      ' Ciclo sui pezzi inseriti
      Dim nVeinId As Integer = nFirstVeinId
      While nVeinId <> GDB_ID.NULL
         ' Assegno Id originale
         EgtSetInfo(nVeinId, KEY_ORI_ID, nFirstPartId + nVeinId - nFirstVeinId)
         ' Nascondo scritte, sono nel layer "Region"
         Dim nVeinRegId As Integer = EgtGetFirstNameInGroup(nVeinId, NAME_REGION)
         Dim nCurrId As Integer = EgtGetFirstInGroup(nVeinRegId)
         While nCurrId <> GDB_ID.NULL
            If EgtGetType(nCurrId) = GDB_TY.EXT_TEXT Then EgtSetStatus(nCurrId, GDB_ST.OFF)
            nCurrId = EgtGetNext(nCurrId)
         End While
         ' Nascondo layer con valori angoli dei lati
         nCurrId = EgtGetFirstNameInGroup(nVeinId, SIDE_ANGLE_LAYER)
         EgtSetStatus(nCurrId, GDB_ST.OFF)
         ' Passo al pezzo successivo
         nVeinId = EgtGetNextPart(nVeinId)
      End While
      ' Se necessario, ripristino il contesto originale
      If nCurrCtx > 0 Then EgtSetCurrentContext(nCurrCtx)
      Return True
   End Function

   Friend Function AddPartFromDraw(nPartId As Integer) As Boolean
      ' Verifico esista il contesto del VeinMatching
      If m_nVeinCtx = 0 Then Return True
      ' Se esiste già il pezzo nel VM, esco
      If GetVeinPartId(nPartId) <> GDB_ID.NULL Then Return True
      ' Verifico validità pezzo
      If nPartId = GDB_ID.NULL Then Return False
      ' Salvo il pezzo su file temporaneo
      Dim sTmpDir As String = String.Empty
      If Not EgtGetTempDir(sTmpDir) Then Return False
      Dim sTmpFile As String = sTmpDir & "\FlatPartVme.Nge"
      EgtSetStatus(nPartId, GDB_ST.ON_)
      EgtSaveObjToFile(nPartId, sTmpFile, NGE.BIN)
      ' Carico il file nel VM
      Dim bOk As Boolean = My.Computer.FileSystem.FileExists(sTmpFile)
      If bOk Then
         bOk = AddPart(sTmpFile, nPartId)
         ' Ne aggiorno la visualizzazione
         ZoomAll()
         ' Cancello il file
         My.Computer.FileSystem.DeleteFile(sTmpFile)
      End If
      Return bOk
   End Function

   Friend Function UpdatePart(nPartId As Integer) As Boolean
      ' Verifico esista il contesto del VeinMatching
      If m_nVeinCtx = 0 Then Return True
      ' Recupero il contesto corrente (principale)
      Dim nCurrCtx = EgtGetCurrentContext()
      ' Recupero il nome originale del pezzo
      Dim nOriId As Integer = nPartId
      EgtGetInfo(nPartId, KEY_ORI_ID, nOriId)
      EgtSetInfo(nPartId, KEY_ORI_ID, nPartId)
      ' Recupero il pezzo nel VeinMatching
      EgtSetCurrentContext(m_nVeinCtx)
      Dim nId = GetVeinPartId(nOriId)
      If nId <> GDB_ID.NULL Then EgtSetInfo(nId, KEY_ORI_ID, nPartId)
      ' Se necessario, ripristino il contesto originale
      If nCurrCtx > 0 Then EgtSetCurrentContext(nCurrCtx)
      Return True
   End Function

   Friend Function OnInsertPartInRaw(nPartId As Integer, Optional bDeselect As Boolean = True) As Boolean
      ' Verifico esista il contesto del VeinMatching
      If m_nVeinCtx = 0 Then Return True
      ' Recupero il contesto corrente (principale)
      Dim nMainCtx = EgtGetCurrentContext()
      ' Se non c'è la fotografia, esco
      Dim nPhotoId As Integer = m_MainWindow.m_CurrentProjectPageUC.GetPhoto()
      If nPhotoId = GDB_ID.NULL Then Return If(bDeselect, OnDeselectPart(nPartId), True)
      ' Recupero il nome originale del pezzo
      Dim nOriId As Integer = nPartId
      EgtGetInfo(nPartId, KEY_ORI_ID, nOriId)
      ' Verifico se esiste già la foto del progetto corrente nel VeinMatching
      Dim sPhoto As String = String.Empty
      EgtGetPhotoPath(nPhotoId, sPhoto)
      Dim sVeinPhoto As String = String.Empty
      GetVeinPhotoPath(sVeinPhoto)
      ' Se necessario, copio la foto
      If String.Compare(sPhoto, sVeinPhoto, True) <> 0 Then
         If Not CopyPhoto(nPhotoId) Then Return False
      End If
      ' Recupero il pezzo nel VeinMatching
      EgtSetCurrentContext(m_nVeinCtx)
      Dim nId = GetVeinPartId(nOriId)
      If nId <> GDB_ID.NULL Then
         ' Recupero la regione del pezzo
         Dim nRegId As Integer = GetVeinPartRegionId(nId)
         ' Gli assegno la texture della foto
         EgtSetTextureName(nRegId, GetPhotoName())
         ' Sistemo il riferimento della texture
         Dim refTxr As New Frame3d
         GetVeinRefPhoto(nMainCtx, nPartId, nId, refTxr)
         EgtSetTextureFrame(nRegId, refTxr, GDB_RT.GLOB)
         ' Sistemo il colore
         Dim colWhite As New Color3d(255, 255, 255, 100)
         EgtSetColor(nRegId, colWhite)

         ' Ripeto le stesse operazioni con il solido del pezzo, se esiste
         Dim nSolidId As Integer = GetVeinPartSolidId(nId)
         If nSolidId <> GDB_ID.NULL Then
            EgtSetTextureName(nSolidId, GetPhotoName())
            EgtSetTextureFrame(nSolidId, refTxr, GDB_RT.GLOB)
            EgtSetColor(nSolidId, colWhite)
         End If

         ' Se richiesto, eseguo deselezione
         If bDeselect Then EgtDeselectObj(nId)
         End If
         EgtDraw()
      EgtSetCurrentContext(nMainCtx)
      Return True
   End Function

   Friend Function OnMovePartInRaw(nPartId As Integer) As Boolean
      ' Verifico esista il contesto del VeinMatching
      If m_nVeinCtx = 0 Then Return True
      ' Recupero il contesto corrente (principale)
      Dim nMainCtx = EgtGetCurrentContext()
      ' Se non c'è la fotografia, esco
      Dim nPhotoId As Integer = m_MainWindow.m_CurrentProjectPageUC.GetPhoto()
      If nPhotoId = GDB_ID.NULL Then Return True
      ' Recupero il nome originale del pezzo
      Dim nOriId As Integer = nPartId
      EgtGetInfo(nPartId, KEY_ORI_ID, nOriId)
      ' Recupero il pezzo nel VeinMatching
      EgtSetCurrentContext(m_nVeinCtx)
      Dim nId = GetVeinPartId(nOriId)
      If nId <> GDB_ID.NULL Then
         ' Recupero la regione e il solido del pezzo
         Dim nRegId As Integer = GetVeinPartRegionId(nId)
         Dim nSolidId As Integer = GetVeinPartSolidId(nId)
         ' Sistemo il riferimento della texture
         Dim refTxr As New Frame3d
         GetVeinRefPhoto(nMainCtx, nPartId, nId, refTxr)
         EgtSetTextureFrame(nRegId, refTxr, GDB_RT.GLOB)
         If nSolidId <> GDB_ID.NULL Then
            EgtSetTextureFrame(nSolidId, refTxr, GDB_RT.GLOB)
         End If
      End If
      EgtDraw()
      EgtSetCurrentContext(nMainCtx)
      Return True
   End Function

   Friend Function OnRemovePartFromRaw(nPartId As Integer, Optional bDeselect As Boolean = True) As Boolean
      ' Verifico esista il contesto del VeinMatching
      If m_nVeinCtx = 0 Then Return True
      ' Recupero il contesto corrente (principale)
      Dim nMainCtx = EgtGetCurrentContext()
      ' Se non c'è la fotografia, esco
      Dim nPhotoId As Integer = m_MainWindow.m_CurrentProjectPageUC.GetPhoto()
      If nPhotoId = GDB_ID.NULL Then Return If(bDeselect, OnDeselectPart(nPartId), True)
      ' Recupero il nome originale del pezzo
      Dim nOriId As Integer = nPartId
      EgtGetInfo(nPartId, KEY_ORI_ID, nOriId)
      ' Tolgo la texture dal pezzo
      EgtSetCurrentContext(m_nVeinCtx)
      Dim nId As Integer = GetVeinPartId(nOriId)
      If nId <> GDB_ID.NULL Then
         ' Recupero la regione del pezzo
         Dim nRegId As Integer = GetVeinPartRegionId(nId)
         ' Gli tolgo la texture
         EgtRemoveTextureData(nRegId)
         ' Sistemo il colore
         Dim colAqua As New Color3d(0, 255, 255, 25)
         EgtSetColor(nRegId, colAqua)

         ' ripeto per il solido
         Dim nSolidId As Integer = GetVeinPartSolidId(nId)
         EgtRemoveTextureData(nSolidId)
         Dim colSolid As Color3d
         EgtGetColor(EgtGetParent(nRegId), colSolid)
         EgtSetColor(nSolidId, colSolid)

         ' Se richiesto, eseguo deselezione
         If bDeselect Then EgtDeselectObj(nId)
      End If
      EgtDraw()
      EgtSetCurrentContext(nMainCtx)
      Return True
   End Function

   Friend Function OnSelectPart(nPartId As Integer, Optional bDraw As Boolean = True) As Boolean
      ' Verifico esista il contesto del VeinMatching
      If m_nVeinCtx = 0 Then Return True
      ' Recupero il contesto corrente (principale)
      Dim nMainCtx = EgtGetCurrentContext()
      ' Recupero il nome originale del pezzo
      Dim nOriId As Integer = nPartId
      EgtGetInfo(nPartId, KEY_ORI_ID, nOriId)
      ' Recupero il pezzo nel VeinMatching
      EgtSetCurrentContext(m_nVeinCtx)
      Dim nId = GetVeinPartId(nOriId)
      Dim bFound As Boolean = nId <> GDB_ID.NULL
      ' Lo seleziono e aggiorno visualizzazione
      If bFound Then
         EgtSelectObj(nId)
         If bDraw Then EgtDraw()
      End If
      ' Ritorno al contesto originale
      EgtSetCurrentContext(nMainCtx)
      Return bFound
   End Function

   Friend Function OnDeselectPart(nPartId As Integer) As Boolean
      ' Verifico esista il contesto del VeinMatching
      If m_nVeinCtx = 0 Then Return True
      ' Recupero il contesto corrente (principale)
      Dim nMainCtx = EgtGetCurrentContext()
      ' Recupero il nome originale del pezzo
      Dim nOriId As Integer = nPartId
      EgtGetInfo(nPartId, KEY_ORI_ID, nOriId)
      ' Recupero il pezzo nel VeinMatching
      EgtSetCurrentContext(m_nVeinCtx)
      Dim nId = GetVeinPartId(nOriId)
      Dim bFound As Boolean = nId <> GDB_ID.NULL
      ' Lo seleziono
      If bFound Then EgtDeselectObj(nId)
      ' Aggiorno visualizzazione e ritorno al contesto originale
      EgtDraw()
      EgtSetCurrentContext(nMainCtx)
      Return bFound
   End Function

   Friend Function OnSelectAll() As Boolean
      ' Verifico esista il contesto del VeinMatching
      If m_nVeinCtx = 0 Then Return True
      ' Imposto VeinMatching context
      Dim nCurrCtx = SetVeinContext()
      If nCurrCtx = 0 Then Return False
      ' Eseguo selezione di tutti i pezzi
      EgtSelectAll()
      EgtDraw()
      ' Se necessario, ripristino il contesto originale
      If nCurrCtx > 0 Then EgtSetCurrentContext(nCurrCtx)
      Return True
   End Function

   Friend Function OnDeselectAll() As Boolean
      ' Verifico esista il contesto del VeinMatching
      If m_nVeinCtx = 0 Then Return True
      ' Imposto VeinMatching context
      Dim nCurrCtx = SetVeinContext()
      If nCurrCtx = 0 Then Return False
      ' Eseguo deselezione di tutti i pezzi
      EgtDeselectAll()
      EgtDraw()
      ' Se necessario, ripristino il contesto originale
      If nCurrCtx > 0 Then EgtSetCurrentContext(nCurrCtx)
      Return True
   End Function

   Friend Function AssemblyParts(ByVal ThicknessRaw As Double) As Boolean

      CreateListAlzAndFront()
      LinkReferencesOnAlette()

      EgtSetCurrentContext(m_nVeinCtx)

      ' costruisco tutti i piani cucina 
      Dim nId As Integer = EgtGetFirstPart()
      While nId <> GDB_ID.NULL
         Dim sInfoName As String = String.Empty
         EgtGetInfo(nId, "CMP", sInfoName)
         ' verifico che il pezzo sia una piano cucina 
         If sInfoName.Contains("PCucina") Then
            If Not CreateKitchenTop(nId, ThicknessRaw) Then Return False
         End If
         ' altrimenti passo al pezzo successivo
         nId = EgtGetNextPart(nId)
      End While

      ' costruisco alzatine e frontalini
      Dim Item As Aletta
      For Each Item In m_ListAlzFront
         ' verifico che il disegno 3D non sia già stato fatto 
         Dim nInfo3D As Integer = 0
         EgtGetInfo(Item.SideId, "Info3D", nInfo3D)
         If nInfo3D <> 1 Then
            EgtSetInfo(Item.SideId, "Info3D", 1)
            ' creo il solido 
            If Not CreateAlettaSolid(Item, ThicknessRaw) Then Return False
            ' posiziono il solido 
            If Not MoveAlettaSolid(Item, ThicknessRaw) Then Return False
         End If
      Next
      Draw()
      Return True
   End Function

   Friend Function CreateKitchenTop(ByRef nId As Integer, ByRef ThicknessRaw As Double) As Boolean

      ' creo o svuoto layer per facce del solido
      Dim nSolidGrp As Integer = EgtGetFirstNameInGroup(nId, NAME_VM_SOLID)
      If nSolidGrp <> GDB_ID.NULL Then
         EgtEmptyGroup(nSolidGrp)
      Else
         nSolidGrp = EgtCreateGroup(nId)
         EgtSetName(nSolidGrp, NAME_VM_SOLID)
      End If

      ' recupero faccia top
      Dim nRegGrp As Integer = EgtGetFirstNameInGroup(nId, NAME_REGION)
      Dim nTopFr As Integer = EgtGetFirstInGroup(nRegGrp)
      While nTopFr <> GDB_ID.NULL
         If EgtGetType(nTopFr) = GDB_TY.SRF_FRGN Then Exit While
         nTopFr = EgtGetNext(nTopFr)
      End While
      If nTopFr = GDB_ID.NULL Then Return False
      EgtSetStatus(nTopFr, 0)

      ' setto colore per il solido
      Dim cCol As New Color3d
      EgtGetColor(nTopFr, cCol)
      EgtSetColor(nSolidGrp, cCol)

      ' creo il solido
      Dim bSameLoopsNbr As Boolean
      Dim nSolidId As Integer
      If Not CreateKitchenBaseSolid(nTopFr, nSolidGrp, ThicknessRaw, nSolidId, bSameLoopsNbr) Then Return False

      ' aggiungo componenti interni
      If Not AddInternalComponents(nSolidId, nTopFr, bSameLoopsNbr, ThicknessRaw) Then Return False

      ' setto eventuale texture 
      Dim sTextName As String = String.Empty
      EgtGetTextureName(nTopFr, sTextName)
      If sTextName <> String.Empty Then
         Dim frText As New Frame3d
         EgtGetTextureFrame(nTopFr, nRegGrp, frText)
         EgtSetTextureName(nSolidId, sTextName)
         EgtSetTextureFrame(nSolidId, frText)
      End If

      ' elimino curve ausiliarie 
      Dim nIdx As Integer = EgtGetFirstInGroup(nSolidGrp)
      While nIdx <> GDB_ID.NULL
         Dim newId As Integer = EgtGetNext(nIdx)
         If EgtGetType(nIdx) <> GDB_TY.SRF_MESH Then
            EgtErase(nIdx)
         End If
         nIdx = newId
      End While

      Dim nOutloopGrpOrig As Integer = EgtGetFirstNameInGroup(nId, NAME_OUTLOOP & ".orig")
      If nOutloopGrpOrig <> GDB_ID.NULL Then
         EgtSetStatus(nOutloopGrpOrig, 1)
         Dim nOutloopGrp As Integer = EgtGetFirstNameInGroup(nId, NAME_OUTLOOP)
         EgtSetStatus(nOutloopGrp, 0)
      End If

      Return True

   End Function

   Friend Function CreateKitchenBaseSolid(ByRef nTopFr As Integer, ByRef nSolidGrp As Integer, ByRef ThicknessRaw As Double,
                                          ByRef nSolidStm As Integer, ByRef bSameLoopsNbr As Boolean) As Boolean

      ' creo la faccia bottom
      Dim nBottomFr As Integer
      Dim nPartId As Integer = EgtGetParent(EgtGetParent(nTopFr))
      If Not EgtCalcFlatPartDownRegion(nPartId, ThicknessRaw) Then Return False
      Dim nDwnRegGrp As Integer = EgtGetFirstNameInGroup(nPartId, "DwnReg")
      If nDwnRegGrp <> GDB_ID.NULL Then
         EgtSetStatus(nDwnRegGrp, 0)
         nBottomFr = EgtGetFirstInGroup(nDwnRegGrp)
         If nBottomFr = GDB_ID.NULL Then Return False
      Else
         nBottomFr = EgtCopy(nTopFr, nSolidGrp)
      End If
      Dim vtMove As Vector3d = -ThicknessRaw * Vector3d.Z_AX()
      EgtMove(nBottomFr, vtMove)
      EgtSetStatus(nBottomFr, 0)

      ' superficie laterale 
      Dim nTopCrvCount, nBottomCrvCount As Integer
      Dim nTopCrv, nBottomCrv As Integer
      nTopCrv = EgtExtractSurfFrChunkLoops(nTopFr, 0, nSolidGrp, nTopCrvCount)
      nBottomCrv = EgtExtractSurfFrChunkLoops(nBottomFr, 0, nSolidGrp, nBottomCrvCount)
      ' modifico il punto iniziale della curva bottom per ottenere una buona superficie rigata
      Dim ptStartTop As Point3d
      EgtStartPoint(nTopCrv, ptStartTop)
      EgtChangeClosedCurveStartPoint(nBottomCrv, ptStartTop - vtMove)
      Dim nLateralStm As Integer = EgtCreateSurfTmRuled(nSolidGrp, nBottomCrv, nTopCrv, 0, EPS_STM)

      ' superfici trimesh per faccia top e bottom
      Dim nTopStm, nBottomStm As Integer
      bSameLoopsNbr = (nTopCrvCount = nBottomCrvCount)
      If bSameLoopsNbr Then
         If Not GetSrfTmFromFlatRegion(nTopFr, nSolidGrp, nTopStm) Then Return False
         If Not GetSrfTmFromFlatRegion(nBottomFr, nSolidGrp, nBottomStm) Then Return False
      Else
         ' creo le facce top e bottom dimenticando eventuali aperture
         nTopStm = EgtCreateSurfTmByFlatContour(nSolidGrp, nTopCrv, EPS_STM)
         nBottomStm = EgtCreateSurfTmByFlatContour(nSolidGrp, nBottomCrv, EPS_STM)
      End If
      EgtInvertSurface(nBottomStm)

      nSolidStm = EgtCreateSurfTmBySewing(nSolidGrp, 3, {nTopStm, nBottomStm, nLateralStm}, True)
      Return nSolidStm <> GDB_ID.NULL

   End Function

   Friend Function AddInternalComponents(ByRef nSolidStm As Integer, ByRef nTopFr As Integer, ByRef bSameLoopsNbr As Boolean,
                                         ByRef ThicknessRaw As Double) As Boolean

      Dim nSolidGrp = EgtGetParent(nSolidStm)

      ' aperture interne  
      Dim nTopCrvCount As Integer
      Dim nTopCrv As Integer = EgtExtractSurfFrChunkLoops(nTopFr, 0, nSolidGrp, nTopCrvCount)
      If bSameLoopsNbr Then
         Dim FacesStm(nTopCrvCount - 1) As Integer
         FacesStm(0) = nSolidStm
         ' creo le superfici laterali definite dalle aperture 
         For i As Integer = 1 To nTopCrvCount - 1
            FacesStm(i) = EgtCreateSurfTmByExtrusion(nSolidGrp, 1, {nTopCrv + i}, -ThicknessRaw * Vector3d.Z_AX(), EPS_STM)
            EgtInvertSurface(FacesStm(i))
         Next
         nSolidStm = EgtCreateSurfTmBySewing(nSolidGrp, nTopCrvCount, FacesStm, True)
      Else
         ' creo le aperture per sottrazione di solidi
         For i As Integer = 1 To nTopCrvCount - 1
            Dim nComponentSrf As Integer = EgtCreateSurfTmByRegionExtrusion(nSolidGrp, 1, {nTopCrv + i}, -(ThicknessRaw + 10) * Vector3d.Z_AX(), EPS_STM)
            EgtSurfTmSubtract(nSolidStm, nComponentSrf)
            EgtErase(nComponentSrf)
         Next
      End If

      ' ribassi 
      Dim nId As Integer = EgtGetFirstGroupInGroup(EgtGetParent(nSolidGrp))
      While nId <> GDB_ID.NULL
         Dim sName As String = ""
         EgtGetName(nId, sName)
         If sName <> "Pocket" Then
            nId = EgtGetNextGroup(nId)
            Continue While
         End If
         ' cerco curva composita che definisce il ribasso 
         Dim nCrvCompoId As Integer = EgtGetFirstInGroup(nId)
         While nCrvCompoId <> GDB_ID.NULL
            If EgtGetType(nCrvCompoId) = GDB_TY.CRV_COMPO Then Exit While
            nCrvCompoId = EgtGetNext(nCrvCompoId)
         End While

         Dim dThick As Double
         EgtCurveThickness(nCrvCompoId, dThick)
         Dim vtExtr As Vector3d
         EgtCurveExtrusion(nCrvCompoId, vtExtr)
         Dim nRecessSrf As Integer = EgtCreateSurfTmByRegionExtrusion(nId, 1, {nCrvCompoId}, (dThick + 100) * vtExtr, EPS_STM)
         EgtSurfTmSubtract(nSolidStm, nRecessSrf)
         EgtErase(nRecessSrf)

         ' Passo al pezzo successivo
         nId = EgtGetNextGroup(nId)
      End While

      Return True
   End Function
   Friend Function GetSrfTmFromFlatRegion(ByRef nFlatRegion As Integer, ByRef nSolidGrp As Integer, ByRef nSrfTmId As Integer) As Boolean

      If nFlatRegion = GDB_ID.NULL Then Return False
      ' curve che delimitano la superficie
      Dim nCrvCount As Integer
      Dim nCrv As Integer = EgtExtractSurfFrChunkLoops(nFlatRegion, 0, nSolidGrp, nCrvCount)
      If nCrv = GDB_ID.NULL Then Return False
      ' creo array con gli indici delle curve 
      Dim CrvList(nCrvCount - 1) As Integer
      For i As Integer = 0 To nCrvCount - 1
         CrvList(i) = nCrv + i
      Next
      nSrfTmId = EgtCreateSurfTmByRegion(nSolidGrp, CrvList, EPS_STM)
      ' cancello le curve create 
      For i As Integer = 0 To nCrvCount - 1
         EgtErase(CrvList(i))
      Next

      Return nSrfTmId <> GDB_ID.NULL

   End Function

   Friend Function CreateAlettaSolid(ByRef Item As Aletta, ByRef ThicknessRaw As Double) As Boolean

      ' angoli per i tagli
      Dim dAngL, dAngR, dAng As Double
      EgtGetInfo(Item.SideId + 1, INFO_SIDE_ANGLE, dAngR)
      EgtGetInfo(Item.SideId + 3, INFO_SIDE_ANGLE, dAngL)
      EgtGetInfo(Item.SideId, INFO_SIDE_ANGLE, dAng)

      If Math.Abs(dAngL - 90) < EPS_SMALL Or Math.Abs(dAngL + 90) < EPS_SMALL Then dAngL = 0
      If Math.Abs(dAngR - 90) < EPS_SMALL Or Math.Abs(dAngR + 90) < EPS_SMALL Then dAngR = 0
      If Math.Abs(dAng - 90) < EPS_SMALL Or Math.Abs(dAng + 90) < EPS_SMALL Then dAng = 0

      ' punti che delimitano la front face (faccia adiacente a top lungo il lato di riferimento)
      Dim pt1, pt2, pt3, pt4 As Point3d
      EgtStartPoint(Item.SideId, pt4)
      EgtEndPoint(Item.SideId, pt3)
      pt2 = pt3 - ThicknessRaw * Vector3d.Z_AX()
      pt1 = pt4 - ThicknessRaw * Vector3d.Z_AX()

      ' aggiungo tagli inclinati
      pt2 = pt2 + ThicknessRaw * Math.Tan(dAngR * Math.PI / 180) * Vector3d.X_AX()
      pt1 = pt1 - ThicknessRaw * Math.Tan(dAngL * Math.PI / 180) * Vector3d.X_AX()

      ' aggiungo eventuale taglio sul lato superiore  
      pt2 = pt2 - ThicknessRaw * Math.Tan(dAng * Math.PI / 180) * Vector3d.Y_AX()
      pt1 = pt1 - ThicknessRaw * Math.Tan(dAng * Math.PI / 180) * Vector3d.Y_AX()

      ' punti che delimitano back face
      Dim HeightTop As Double
      EgtCurveLength(Item.SideId + 1, HeightTop)
      Dim HeightBottom As Double = HeightTop + ThicknessRaw * Math.Tan(dAng * Math.PI / 180)
      Dim ptB1 As Point3d = pt1 + HeightBottom * Vector3d.Y_AX()
      Dim ptB2 As Point3d = pt2 + HeightBottom * Vector3d.Y_AX()
      Dim ptB3 As Point3d = pt3 + HeightTop * Vector3d.Y_AX()
      Dim ptB4 As Point3d = pt4 + HeightTop * Vector3d.Y_AX()

      ' Creo o svuoto layer per facce del solido
      Dim nSolidGrp As Integer = EgtGetFirstNameInGroup(Item.PartId, NAME_VM_SOLID)
      If nSolidGrp <> GDB_ID.NULL Then
         EgtEmptyGroup(nSolidGrp)
      Else
         nSolidGrp = EgtCreateGroup(Item.PartId)
         EgtSetName(nSolidGrp, NAME_VM_SOLID)
      End If
      Dim nRegionGrp As Integer = EgtGetFirstNameInGroup(Item.PartId, NAME_REGION)
      Dim cCol As New Color3d
      EgtGetColor(EgtGetFirstInGroup(nRegionGrp), cCol)
      EgtSetColor(nSolidGrp, cCol)

      ' Top Face
      Dim nTopSrfFR As Integer = EgtGetFirstInGroup(nRegionGrp)
      Dim tmp As Integer
      Dim nTopCrv As Integer = EgtExtractSurfFrChunkLoops(nTopSrfFR, 0, nRegionGrp, tmp)
      If nTopCrv = GDB_ID.NULL Then Return False
      Dim nTopSrf As Integer = EgtCreateSurfTmByRegion(nSolidGrp, {nTopCrv}, EPS_SMALL)
      EgtErase(nTopCrv)
      EgtSetStatus(nTopSrfFR, 0)

      Dim nFrontSrf, nBackSrf, nBottomSrf, nRightSrf, nLeftSrf As Integer
      ' Front Face
      If Not CreateSolidFace(nSolidGrp, {pt1, pt2, pt3, pt4}, nFrontSrf, False) Then Return False
      ' Back Face
      If Not CreateSolidFace(nSolidGrp, {ptB1, ptB4, ptB3, ptB2}, nBackSrf) Then Return False
      ' Bottom face
      If Not CreateSolidFace(nSolidGrp, {pt2, pt1, ptB1, ptB2}, nBottomSrf) Then Return False
      ' Right face
      If Not CreateSolidFace(nSolidGrp, {ptB1, pt1, pt4, ptB4}, nRightSrf) Then Return False
      ' Left face
      If Not CreateSolidFace(nSolidGrp, {ptB2, ptB3, pt3, pt2}, nLeftSrf) Then Return False

      ' creo il solido 
      Dim nSolidSrf As Integer = EgtCreateSurfTmBySewing(nSolidGrp, 6, {nTopSrf, nFrontSrf, nBackSrf, nBottomSrf, nRightSrf, nLeftSrf}, True)

      ' setto eventuale texture 
      Dim sTextName As String = String.Empty
      EgtGetTextureName(nTopSrfFR, sTextName)
      If sTextName <> String.Empty Then
         Dim frText As New Frame3d
         EgtGetTextureFrame(nTopSrfFR, nRegionGrp, frText)
         EgtSetTextureName(nSolidSrf, sTextName)
         EgtSetTextureFrame(nSolidSrf, frText)
      End If

      Dim nOutloopGrp As Integer = EgtGetParent(Item.SideId)
      EgtSetStatus(nOutloopGrp, 0)

      Return True
   End Function

   Friend Function CreateSolidFace(ByRef nSrfGrp As Integer, ByRef Points As Point3d(), ByRef nSrfId As Integer,
                                   Optional ByRef bDeleteCrv As Boolean = True) As Boolean

      If Points.Count() <> 4 Then Return False

      Dim nCrvId As Integer = EgtCreateCurveCompo(nSrfGrp, {EgtCreateLine(nSrfGrp, Points(0), Points(1)),
                                                            EgtCreateLine(nSrfGrp, Points(1), Points(2)),
                                                            EgtCreateLine(nSrfGrp, Points(2), Points(3)),
                                                            EgtCreateLine(nSrfGrp, Points(3), Points(0))}, True)

      If nCrvId = GDB_ID.NULL Then Return False
      nSrfId = EgtCreateSurfTmByRegion(nSrfGrp, {nCrvId}, EPS_SMALL)
      If bDeleteCrv Then
         EgtErase(nCrvId)
      Else
         EgtSetStatus(nCrvId, GDB_ST.OFF)
      End If
      Return nSrfId <> GDB_ID.NULL
   End Function

   Friend Function MoveAlettaSolid(ByRef Item As Aletta, ByRef ThicknessRaw As Double) As Boolean

      Dim nType As Integer
      If Not EgtGetInfo(Item.IdSideRef, "AF", nType) Then Return False

      Dim ptSRef, ptERef, ptE As Point3d
      If Not EgtStartPoint(Item.IdSideRef, GDB_ID.ROOT, ptSRef) Then Return False
      If Not EgtEndPoint(Item.IdSideRef, GDB_ID.ROOT, ptERef) Then Return False
      If Not EgtEndPoint(Item.SideId, GDB_ID.ROOT, ptE) Then Return False

      ' ruoto il solido intorno al lato di riferimento
      Dim vtRot As Vector3d = ptERef - ptSRef
      If nType = 1 Then
         EgtRotate(Item.PartId, ptE, vtRot, -90, GDB_RT.GLOB)
      ElseIf nType = 2 Then
         EgtRotate(Item.PartId, ptE, vtRot, 90, GDB_RT.GLOB)
      End If

      ' punto di riferimento per la traslazione sul solido
      Dim ptSolid As Point3d
      If nType = 1 Then
         ' cerco id della curva che definisce la front face
         Dim nSolidGrp As Integer = EgtGetFirstNameInGroup(Item.PartId, NAME_VM_SOLID)
         Dim nFrontCrvId As Integer = EgtGetFirstInGroup(nSolidGrp)
         EgtStartPoint(nFrontCrvId, ptSolid)
      ElseIf nType = 2 Then
         EgtStartPoint(Item.SideId, ptSolid)
      End If

      Dim ItemFrame As New Frame3d
      If Not EgtGetGroupGlobFrame(Item.PartId, ItemFrame) Then Return False
      ptSolid.ToGlob(ItemFrame)

      'punto di riferimento per la traslazione sul piano cucina
      Dim ptKitchen As Point3d = ptERef
      ' traslazione
      Dim vtMove As Vector3d = ptKitchen - ptSolid
      EgtMove(Item.PartId, vtMove, GDB_RT.GLOB)

      Return True
   End Function

   Friend Function Draw() As Boolean
      ' Verifico esista il contesto del VeinMatching
      If m_nVeinCtx = 0 Then Return True
      ' Imposto VeinMatching context
      Dim nCurrCtx = SetVeinContext()
      If nCurrCtx = 0 Then Return False
      ' Eseguo Zoom
      EgtDraw()
      ' Se necessario, ripristino il contesto originale
      If nCurrCtx > 0 Then EgtSetCurrentContext(nCurrCtx)
      Return True
   End Function

   Friend Function ZoomAll() As Boolean
      ' Verifico esista il contesto del VeinMatching
      If m_nVeinCtx = 0 Then Return True
      ' Imposto VeinMatching context
      Dim nCurrCtx = SetVeinContext()
      If nCurrCtx = 0 Then Return False
      ' Eseguo Zoom
      EgtZoom(ZM.ALL)
      ' Se necessario, ripristino il contesto originale
      If nCurrCtx > 0 Then EgtSetCurrentContext(nCurrCtx)
      Return True
   End Function

   Friend Function Open(sFilePath As String) As Boolean
      ' Verifico esista il contesto del VeinMatching
      If m_nVeinCtx = 0 Then Return True
      ' Recupero il contesto corrente (principale)
      Dim nMainCtx = EgtGetCurrentContext()
      ' Apro il file
      EgtSetCurrentContext(m_nVeinCtx)
      Dim bOk As Boolean = EgtOpenFile(sFilePath)
      ' Aggiorno contatore foto
      Dim nPhId As Integer = EgtGetFirstInGroup(EgtGetFirstNameInGroup(GDB_ID.ROOT, PHOTO_GRP))
      While nPhId <> GDB_ID.NULL
         Dim sName As String = String.Empty
         EgtGetName(nPhId, sName)
         Dim nVal As Integer = 0
         If StringToInt(sName.Replace(PHOTO_NAME, ""), nVal) Then m_nPhoto = Math.Max(m_nPhoto, nVal)
         nPhId = EgtGetNext(nPhId)
      End While
      ' Eseguo zoom all
      EgtZoom(ZM.ALL)
      ' Ripristino il contesto originale
      EgtSetCurrentContext(nMainCtx)
      Return bOk
   End Function

   Friend Function Save(sFilePath As String) As Boolean
      ' Verifico esista il contesto del VeinMatching
      If m_nVeinCtx = 0 Then Return True
      ' Recupero il contesto corrente (principale)
      Dim nMainCtx As Integer = EgtGetCurrentContext()
      ' Salvo il file
      EgtSetCurrentContext(m_nVeinCtx)
      Dim bOk As Boolean = EgtSaveFile(sFilePath, NGE.CMPTEXT)
      ' Ripristino il contesto originale
      EgtSetCurrentContext(nMainCtx)
      Return bOk
   End Function

   Friend Function Export(sFilePath As String) As Boolean
      ' Verifico esista il contesto del VeinMatching
      If m_nVeinCtx = 0 Then Return True
      ' Recupero il contesto corrente (principale)
      Dim nMainCtx = EgtGetCurrentContext()
      ' Esporto il file come immagine
      EgtSetCurrentContext(m_nVeinCtx)
      Dim bOk As Boolean = (EgtGetFileType(sFilePath) = FT.IMG)
      bOk = bOk AndAlso EgtGetImage(EgtGetShowMode(), New Color3d(255, 255, 255), New Color3d(255, 255, 255),
                                    m_nImgWidth, m_nImgHeight, sFilePath)
      ' Ripristino il contesto originale
      EgtSetCurrentContext(nMainCtx)
      Return bOk
   End Function

   Private Function GetPhotoName() As String
      Return PHOTO_NAME & m_nPhoto.ToString()
   End Function

   Private Function CopyPhoto(nPhotoId As Integer) As Boolean
      ' Recupero il contesto corrente
      Dim nCurrCtx = EgtGetCurrentContext()
      ' Recupero i dati della fotografia
      Dim sPath As String = String.Empty
      If Not EgtGetPhotoPath(nPhotoId, sPath) OrElse Not File.Exists(sPath) Then Return False
      Dim ptOri As Point3d
      If Not EgtGetPhotoOrigin(nPhotoId, ptOri) Then Return False
      Dim ptCen As Point3d
      If Not EgtGetPhotoCenter(nPhotoId, ptCen) Then Return False
      Dim dDimX, dDimY As Double
      If Not EgtGetPhotoDimensions(nPhotoId, dDimX, dDimY) Then Return False
      Dim ptMin, ptMax As Point3d
      If Not EgtGetBBoxGlob(nPhotoId, GDB_BB.STANDARD, ptMin, ptMax) Then Return False
      ' Passo al contesto del VeinMatching
      EgtSetCurrentContext(m_nVeinCtx)
      ' Se non esiste il gruppo per le foto, lo creo
      Dim nPhGrpId As Integer = EgtGetFirstNameInGroup(GDB_ID.ROOT, PHOTO_GRP)
      If nPhGrpId = GDB_ID.NULL Then
         nPhGrpId = EgtCreateGroup(GDB_ID.ROOT)
         If nPhGrpId = GDB_ID.NULL Then
            EgtSetCurrentContext(nCurrCtx)
            Return False
         End If
         EgtSetName(nPhGrpId, PHOTO_GRP)
      End If
      EgtSetLevel(nPhGrpId, GDB_LV.SYSTEM)
      EgtSetStatus(nPhGrpId, GDB_ST.OFF)
      ' Carico la fotografia
      m_nPhoto += 1
      Dim nNewId As Integer = EgtAddPhoto2(GetPhotoName(), sPath, ptOri, ptCen, dDimX, dDimY, nPhGrpId, ptMin, ptMax)
      ' Ritorno al contesto corrente
      EgtSetCurrentContext(nCurrCtx)
      Return nNewId <> GDB_ID.NULL
   End Function

   Private Function SetVeinContext() As Integer
      ' Verifico esista il contesto del VeinMatching
      If m_nVeinCtx = 0 Then Return 0
      ' Recupero il contesto corrente
      Dim nCurrCtx = EgtGetCurrentContext()
      ' Se necessario, cambio contesto
      If m_nVeinCtx <> nCurrCtx Then
         If EgtSetCurrentContext(m_nVeinCtx) Then
            Return If( nCurrCtx > 0, nCurrCtx, -2)
         Else
            Return 0
         End If
      Else
         Return -1
      End If
   End Function

   Private Function GetVeinPhoto() As Integer
      ' Imposto VeinMatching context
      Dim nCurrCtx = SetVeinContext()
      If nCurrCtx = 0 Then Return GDB_ID.NULL
      ' Recupero Id foto
      Dim nId As Integer = EgtGetFirstNameInGroup(EgtGetFirstNameInGroup(GDB_ID.ROOT, PHOTO_GRP), GetPhotoName())
      ' Ripristino il contesto originale
      EgtSetCurrentContext(nCurrCtx)
      Return nId
   End Function

   Private Function GetVeinPhotoPath(ByRef sPath As String) As Boolean
      ' Imposto VeinMatching context
      Dim nCurrCtx = SetVeinContext()
      If nCurrCtx = 0 Then Return False
      ' Recupero path dell'immagine della foto
      Dim nId As Integer = EgtGetFirstNameInGroup(EgtGetFirstNameInGroup(GDB_ID.ROOT, PHOTO_GRP), GetPhotoName())
      Dim bOk As Boolean = EgtGetPhotoPath(nId, sPath)
      ' Ripristino il contesto originale
      EgtSetCurrentContext(nCurrCtx)
      Return bOk
   End Function

   Private Function GetVeinRefPhoto(nMainCtx As Integer, nPartId As Integer, nVePartId As Integer, ByRef refPhoto As Frame3d) As Boolean
      ' Riferimento della foto rispetto al riferimento del pezzo nel contesto principale
      If Not EgtSetCurrentContext(nMainCtx) Then Return False
      ' riferimento della foto in globale
      If Not m_MainWindow.m_CurrentProjectPageUC.GetPhotoTextureRef(refPhoto) Then Return False
      ' riferimento del pezzo in globale
      Dim nRefId As Integer = EgtGetFirstNameInGroup(EgtGetFirstNameInGroup(nPartId, NAME_REGION), REF_NAME)
      Dim refPart As New Frame3d
      If Not EgtFrame(nRefId, GDB_ID.ROOT, refPart) Then Return False
      ' porto il riferimento della foto in quello del pezzo
      refPhoto.ToLoc(refPart)
      ' Riferimento della foto rispetto al riferimento del pezzo in VeinMatching
      If Not EgtSetCurrentContext(m_nVeinCtx) Then Return False
      ' riferimento del pezzo in globale
      Dim nVeRefId As Integer = EgtGetFirstNameInGroup(EgtGetFirstNameInGroup(nVePartId, NAME_REGION), REF_NAME)
      Dim refVePart As New Frame3d
      If Not EgtFrame(nVeRefId, GDB_ID.ROOT, refVePart) Then Return False
      refPhoto.ToGlob(refVePart)
      Return True
   End Function

   Private Function GetVeinPartId(nPartId As Integer) As Integer
      ' Imposto VeinMatching context
      Dim nCurrCtx = SetVeinContext()
      If nCurrCtx = 0 Then Return GDB_ID.NULL
      ' Cerco il pezzo in Vein che corrisponde al pezzo desiderato
      Dim nId As Integer = EgtGetFirstPart()
      While nId <> GDB_ID.NULL
         Dim nOriId As Integer
         If EgtGetInfo(nId, KEY_ORI_ID, nOriId) AndAlso nOriId = nPartId Then
               Exit While
         End If
         nId = EgtGetNextPart(nId)
      End While
      ' Se necessario, ripristino il contesto originale
      If nCurrCtx > 0 Then EgtSetCurrentContext(nCurrCtx)
      Return nId
   End Function

   Private Function GetVeinPartRegionId(nVeinPartId As Integer) As Integer
      ' Imposto VeinMatching context
      Dim nCurrCtx = SetVeinContext()
      If nCurrCtx = 0 Then Return GDB_ID.NULL
      ' Gruppo regione
      Dim nRegLayId As Integer = EgtGetFirstNameInGroup(nVeinPartId, NAME_REGION)
      ' Entità superficie regione piatta
      Dim nRegId As Integer = EgtGetFirstInGroup(nRegLayId)
      While nRegId <> GDB_ID.NULL
         If EgtGetType(nRegId) = GDB_TY.SRF_FRGN Then
            Exit While
         End If
         nRegId = EgtGetNext(nRegId)
      End While
      ' Se necessario, ripristino il contesto originale
      If nCurrCtx > 0 Then EgtSetCurrentContext(nCurrCtx)
      Return nRegId
   End Function

   Private Function GetVeinPartSolidId(nVeinPartId As Integer) As Integer
      ' Imposto VeinMatching context
      Dim nCurrCtx = SetVeinContext()
      If nCurrCtx = 0 Then Return GDB_ID.NULL
      ' Gruppo regione
      Dim nRegLayId As Integer = EgtGetFirstNameInGroup(nVeinPartId, NAME_VM_SOLID)
      ' Entità superficie regione piatta
      Dim nRegId As Integer = EgtGetFirstInGroup(nRegLayId)
      While nRegId <> GDB_ID.NULL
         If EgtGetType(nRegId) = GDB_TY.SRF_MESH Then
            Exit While
         End If
         nRegId = EgtGetNext(nRegId)
      End While
      ' Se necessario, ripristino il contesto originale
      If nCurrCtx > 0 Then EgtSetCurrentContext(nCurrCtx)
      Return nRegId
   End Function



End Module


Public Class Aletta

   Private m_PartId As Integer = -1
   Public ReadOnly Property PartId As Integer
      Get
         Return m_PartId
      End Get
   End Property

   Private m_SideId As Integer = -1
   Public ReadOnly Property SideId As Integer
      Get
         Return m_SideId
      End Get
   End Property

   Private m_RefGUID As String = String.Empty
   Public ReadOnly Property RefGUID As String
      Get
         Return m_RefGUID
      End Get
   End Property

   Private m_IdSideRef As Integer = -1
   Public Property IdSideRef As Integer
      Get
         Return m_IdSideRef
      End Get
      Set(value As Integer)
         m_IdSideRef = value
      End Set
   End Property

   Sub New(nId As Integer)
      m_PartId = nId

      ' Recupero l'info legata al lato che contiene iil riferiemnto
      Dim nOutLoopLayId As Integer = EgtGetFirstNameInGroup(nId, NAME_OUTLOOP)
      ' Entità lato
      Dim nSideId As Integer = EgtGetFirstInGroup(nOutLoopLayId)
      While nSideId <> GDB_ID.NULL
         Dim sInfoGUID As String = String.Empty
         EgtGetInfo(nSideId, "RefAF", sInfoGUID)
         If Not String.IsNullOrEmpty(sInfoGUID) Then
            m_RefGUID = sInfoGUID
            m_SideId = nSideId
            Exit While
         End If
         nSideId = EgtGetNext(nSideId)
      End While
   End Sub

End Class
