From c58a264d38d1b965c467d23fef98e2cd90925540 Mon Sep 17 00:00:00 2001 From: Miguel Date: Sun, 9 Jun 2024 10:39:31 +0200 Subject: [PATCH] Mejorando sistema de Links entre Objetos. Usando IItemsSource y suscribiendose al evento de cambio de Nombre. De esta forma se mantiene un enlace por string mas simple para serializar --- App.xaml | 38 ++-- MainViewModel.cs | 27 ++- MainWindow.xaml | 47 ++++- MainWindow.xaml.cs | 1 + ObjetosSim/Decorativos/ucTextPlate.xaml.cs | 31 +--- ObjetosSim/Estaticos/ucTransporteTTop.xaml.cs | 64 +++++-- .../ucBuscarCoincidencias.xaml.cs | 146 +++++++++------ .../Extraccion Datos/ucExtraccionTag.xaml.cs | 91 +-------- ObjetosSim/UserControlFactory.cs | 15 +- ObjetosSim/UserControls/OSComboBox.xaml | 12 ++ ObjetosSim/UserControls/OSComboBox.xaml.cs | 127 +++++++++++++ ObjetosSim/osBase.cs | 172 +++++++++++++++++- XAMLhelpers.cs | 1 - estadoPersistente.cs | 18 ++ 14 files changed, 568 insertions(+), 222 deletions(-) create mode 100644 ObjetosSim/UserControls/OSComboBox.xaml create mode 100644 ObjetosSim/UserControls/OSComboBox.xaml.cs diff --git a/App.xaml b/App.xaml index 7bf6453..1dc2e0a 100644 --- a/App.xaml +++ b/App.xaml @@ -1,25 +1,25 @@ - - + + - - - - - - - - - + + + + + + + + + - - + + - + + diff --git a/MainViewModel.cs b/MainViewModel.cs index 7f2a57c..560451d 100644 --- a/MainViewModel.cs +++ b/MainViewModel.cs @@ -109,8 +109,11 @@ namespace CtrEditor DatosDeTrabajo.CargarImagenes(); ListaImagenes = new ObservableCollection(DatosDeTrabajo.Imagenes.Keys); // Actualizar claves SelectedImage = null; - if (ListaImagenes.FirstOrDefault() != null) + if (EstadoPersistente.Instance.imagen != null && EstadoPersistente.Instance.imagen.Length>0) + SelectedImage = EstadoPersistente.Instance.imagen; + else if (ListaImagenes.FirstOrDefault() != null) SelectedImage = ListaImagenes.FirstOrDefault(); + OnPropertyChanged(nameof(directorioTrabajo)); // Notificar el cambio de propiedad OnPropertyChanged(nameof(ListaImagenes)); // Notificar que la lista de imágenes ha cambiado } @@ -131,6 +134,8 @@ namespace CtrEditor // SaveStateObjetosSimulables(); // Guarda el estado antes de cambiar la imagen ImageSelected?.Invoke(this, datosDeTrabajo.Imagenes[value]); // Dispara el evento con la nueva ruta de imagen LoadStateObjetosSimulables(); + EstadoPersistente.Instance.imagen = value; + EstadoPersistente.Instance.GuardarEstado(); } } @@ -331,7 +336,10 @@ namespace CtrEditor private void EliminarUserControl() { if (SelectedItemOsList is osBase objEliminar) + { RemoverObjetoSimulable(objEliminar); + + } } private void InitializeTipoSimulableList() @@ -501,7 +509,7 @@ namespace CtrEditor // Ruta del archivo a ser guardado path = DatosDeTrabajo.ObtenerPathAllPages(".json"); - if (path!=null) + if (path != null) SerializarYSalvar(_objetosSimulablesAllPages, path); // Restaurar las propiedades originales de los objetos @@ -524,6 +532,7 @@ namespace CtrEditor var settings = new JsonSerializerSettings { Formatting = Formatting.Indented, + // PreserveReferencesHandling = PreserveReferencesHandling.Objects, NullValueHandling = NullValueHandling.Ignore, TypeNameHandling = TypeNameHandling.Auto }; @@ -542,12 +551,12 @@ namespace CtrEditor ObjetosSimulables.Clear(); simulationManager.Clear(); if (SelectedImage != null) - { - var settings = new JsonSerializerSettings + { + var settings = new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.Auto, ObjectCreationHandling = ObjectCreationHandling.Replace, - PreserveReferencesHandling = PreserveReferencesHandling.Objects, + // PreserveReferencesHandling = PreserveReferencesHandling.Objects, ConstructorHandling = ConstructorHandling.AllowNonPublicDefaultConstructor }; @@ -555,7 +564,7 @@ namespace CtrEditor if (File.Exists(jsonPath)) { string jsonString = File.ReadAllText(jsonPath); - + var simulationData = JsonConvert.DeserializeObject(jsonString, settings); if (simulationData != null) @@ -576,7 +585,7 @@ namespace CtrEditor } } - jsonPath = DatosDeTrabajo.ObtenerPathAllPages(".json"); + jsonPath = DatosDeTrabajo.ObtenerPathAllPages(".json"); if (File.Exists(jsonPath)) { string jsonString = File.ReadAllText(jsonPath); @@ -585,12 +594,12 @@ namespace CtrEditor _objetosSimulablesAllPages = JsonConvert.DeserializeObject>(jsonString, settings); if (_objetosSimulablesAllPages != null) - foreach(var obj in _objetosSimulablesAllPages) + foreach (var obj in _objetosSimulablesAllPages) ObjetosSimulables.Add(obj); } // Recorrer la colección de objetos simulables foreach (var objetoSimulable in ObjetosSimulables) - CrearUserControlDesdeObjetoSimulable(objetoSimulable); + if (objetoSimulable != null) CrearUserControlDesdeObjetoSimulable(objetoSimulable); } } catch { /* Consider logging the error or handling it appropriately */ } diff --git a/MainWindow.xaml b/MainWindow.xaml index 615722a..59a3017 100644 --- a/MainWindow.xaml +++ b/MainWindow.xaml @@ -3,8 +3,10 @@ xmlns:Siemens="clr-namespace:CtrEditor.Siemens" xmlns:local="clr-namespace:CtrEditor" xmlns:uc="clr-namespace:CtrEditor.ObjetosSim.UserControls" xmlns:xctk="http://schemas.xceed.com/wpf/xaml/toolkit" xmlns:sys="clr-namespace:System;assembly=mscorlib" - xmlns:ObjetosSim="clr-namespace:CtrEditor.ObjetosSim" x:Class="CtrEditor.MainWindow" Height="900" Width="1600" - WindowState="Maximized" ResizeMode="CanResize" Title="{Binding directorioTrabajo}" Icon="/app2.png"> + xmlns:ObjetosSim="clr-namespace:CtrEditor.ObjetosSim" + xmlns:ObjetosExtraccion="clr-namespace:CtrEditor.ObjetosSim.Extraccion_Datos" x:Class="CtrEditor.MainWindow" + Height="900" Width="1600" WindowState="Maximized" ResizeMode="CanResize" Title="{Binding directorioTrabajo}" + Icon="/app2.png"> @@ -32,7 +34,6 @@ - @@ -178,7 +179,8 @@ ResizeDirection="Rows" VerticalAlignment="Center" /> - + @@ -230,16 +232,45 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + - diff --git a/MainWindow.xaml.cs b/MainWindow.xaml.cs index c2bc528..1578eba 100644 --- a/MainWindow.xaml.cs +++ b/MainWindow.xaml.cs @@ -419,6 +419,7 @@ namespace CtrEditor private void ListaOs_SelectionChanged(object sender, SelectionChangedEventArgs e) { //PanelEdicion.Children.Clear(); // Limpiar el panel existente + UserControlFactory.LimpiarPropiedadesosDatos(PanelEdicion); if (e.AddedItems.Count > 0 && e.AddedItems[0] is osBase selectedObject) CargarPropiedadesosDatos(selectedObject); diff --git a/ObjetosSim/Decorativos/ucTextPlate.xaml.cs b/ObjetosSim/Decorativos/ucTextPlate.xaml.cs index 2974eb9..48e6e2c 100644 --- a/ObjetosSim/Decorativos/ucTextPlate.xaml.cs +++ b/ObjetosSim/Decorativos/ucTextPlate.xaml.cs @@ -51,38 +51,11 @@ namespace CtrEditor.ObjetosSim public override void TopChanging(float oldValue, float newValue) { UpdateChildsTop(newValue - oldValue); } - public override void LeftChanging(float oldValue, float newValue) { + public override void LeftChanging(float oldValue, float newValue) + { UpdateChildsLeft(newValue - oldValue); } - protected void UpdateChildsTop(float offsetY) - { - if (!string.IsNullOrEmpty(Nombre) && _mainViewModel != null) - { - foreach (var objetoSimulable in _mainViewModel.ObjetosSimulables) - { - if (objetoSimulable != this && objetoSimulable.Group_Panel == Nombre) - { - objetoSimulable.Top += offsetY; - } - } - } - } - protected void UpdateChildsLeft(float offsetX) - { - if (!string.IsNullOrEmpty(Nombre) && _mainViewModel != null) - { - foreach (var objetoSimulable in _mainViewModel.ObjetosSimulables) - { - if (objetoSimulable != this && objetoSimulable.Group_Panel == Nombre) - { - objetoSimulable.Left += offsetX; - } - } - } - } - - public osTextPlate() { Ancho = 0.5f; diff --git a/ObjetosSim/Estaticos/ucTransporteTTop.xaml.cs b/ObjetosSim/Estaticos/ucTransporteTTop.xaml.cs index 358c288..d41ec16 100644 --- a/ObjetosSim/Estaticos/ucTransporteTTop.xaml.cs +++ b/ObjetosSim/Estaticos/ucTransporteTTop.xaml.cs @@ -7,7 +7,12 @@ using CommunityToolkit.Mvvm.ComponentModel; using CtrEditor.Siemens; using CtrEditor.Simulacion; using System.Windows.Input; +using Newtonsoft.Json; +using System.Collections.Generic; +using Xceed.Wpf.Toolkit.PropertyGrid.Attributes; +using System.ComponentModel; +using System.Xml.Linq; namespace CtrEditor.ObjetosSim { @@ -18,15 +23,17 @@ namespace CtrEditor.ObjetosSim public partial class osTransporteTTop : osBase, IosBase { - private osBase _osMotor = null; private simTransporte SimGeometria; + private osVMmotorSim Motor; public static string NombreClase() { return "Transporte"; } private string nombre = "Transporte TTOP"; + + [property: Category("Id:")] public override string Nombre { get => nombre; @@ -34,6 +41,7 @@ namespace CtrEditor.ObjetosSim } [ObservableProperty] + [property: Category("Simulation:")] public float velocidadActual; partial void OnVelocidadActualChanged(float value) @@ -42,6 +50,7 @@ namespace CtrEditor.ObjetosSim } [ObservableProperty] + [property: Category("Simulation:")] bool invertirDireccion; partial void OnInvertirDireccionChanged(bool value) @@ -63,28 +72,53 @@ namespace CtrEditor.ObjetosSim ActualizarAnimacionStoryBoardTransporte(VelocidadActual); } - [ObservableProperty] - public string motor; + [property: Description("Link to Motor")] + [property: Category("PLC link:")] + [property: ItemsSource(typeof(osBaseItemsSource))] + string id_Motor; - partial void OnMotorChanged(string value) + partial void OnId_MotorChanged(string value) { - _osMotor = ObtenerLink(Motor, typeof(osVMmotorSim)); + if (Motor != null) + Motor.PropertyChanged -= OnMotorPropertyChanged; + if (_mainViewModel != null && value != null && value.Length > 0) + { + Motor = (osVMmotorSim)_mainViewModel.ObjetosSimulables.FirstOrDefault(s => (s is osVMmotorSim && s.Nombre == value), null); + if (Motor != null) + Motor.PropertyChanged += OnMotorPropertyChanged; + } + } + + private void OnMotorPropertyChanged(object sender, PropertyChangedEventArgs e) + { + if (e.PropertyName == nameof(osVMmotorSim.Nombre)) + { + Id_Motor = ((osVMmotorSim)sender).Nombre; + } } [ObservableProperty] + [property: Category("Layout:")] public float ancho; [ObservableProperty] + [property: Category("Layout:")] public float alto; [ObservableProperty] + [property: Category("Layout:")] public float angulo; + [ObservableProperty] + [property: Category("Setup:")] public float frictionCoefficient; [ObservableProperty] + [property: Category("Setup:")] public float velMax50hz; [ObservableProperty] + [property: Category("Setup:")] public float tiempoRampa; [ObservableProperty] + [property: Category("Setup:")] public bool esMarcha; @@ -92,14 +126,14 @@ namespace CtrEditor.ObjetosSim { if (_visualRepresentation is ucTransporteTTop uc) { - UpdateRectangle(SimGeometria, uc.Transporte,Alto,Ancho,Angulo); + UpdateRectangle(SimGeometria, uc.Transporte, Alto, Ancho, Angulo); SetSpeed(); } ActualizarAnimacionStoryBoardTransporte(VelocidadActual); } public osTransporteTTop() - { + { Ancho = 1; Alto = 0.10f; } @@ -117,13 +151,9 @@ namespace CtrEditor.ObjetosSim public override void UpdatePLC(PLCModel plc, int elapsedMilliseconds) { - if (_osMotor != null) - { - if (_osMotor is osVMmotorSim motor) + if (Motor != null) + if (Motor is osVMmotorSim motor) VelocidadActual = motor.Velocidad; - } - else if (Motor.Length > 0) - _osMotor = ObtenerLink(Motor, typeof(osVMmotorSim)); } public override void ucLoaded() @@ -131,11 +161,12 @@ namespace CtrEditor.ObjetosSim // El UserControl ya se ha cargado y podemos obtener las coordenadas para // crear el objeto de simulacion ActualizarLeftTop(); + OnId_MotorChanged(Id_Motor); if (_visualRepresentation is ucTransporteTTop uc) { SimGeometria = AddRectangle(simulationManager, uc.Transporte, Alto, Ancho, Angulo); - CrearAnimacionStoryBoardTrasnporte(uc.Transporte,InvertirDireccion); + CrearAnimacionStoryBoardTrasnporte(uc.Transporte, InvertirDireccion); } } public override void ucUnLoaded() @@ -178,7 +209,8 @@ namespace CtrEditor.ObjetosSim Datos.Top = PixelToMeter.Instance.calc.PixelsToMeters(TopPixels); } } - public void Rotate(float Angle) { + public void Rotate(float Angle) + { if (Datos != null) if (Datos is osTransporteTTop datos) datos.Angulo = Angle; @@ -190,6 +222,8 @@ namespace CtrEditor.ObjetosSim } } + + } diff --git a/ObjetosSim/Extraccion Datos/ucBuscarCoincidencias.xaml.cs b/ObjetosSim/Extraccion Datos/ucBuscarCoincidencias.xaml.cs index a5085eb..cf16f2e 100644 --- a/ObjetosSim/Extraccion Datos/ucBuscarCoincidencias.xaml.cs +++ b/ObjetosSim/Extraccion Datos/ucBuscarCoincidencias.xaml.cs @@ -15,6 +15,8 @@ using Point = System.Drawing.Point; using Rectangle = System.Windows.Shapes.Rectangle; using Size = System.Drawing.Size; using Ookii.Dialogs.Wpf; +using Rect = System.Windows.Rect; +using System.ComponentModel; namespace CtrEditor.ObjetosSim.Extraccion_Datos @@ -26,15 +28,15 @@ namespace CtrEditor.ObjetosSim.Extraccion_Datos public partial class osBuscarCoincidencias : osBase, IosBase { - private osBase _osMotor = null; - - private simTransporte SimGeometria; + [ObservableProperty] + List search_rectangles; public static string NombreClase() { return "Search Templates"; } private string nombre = NombreClase(); + public override string Nombre { get => nombre; @@ -51,51 +53,54 @@ namespace CtrEditor.ObjetosSim.Extraccion_Datos Search_templates = false; } - public override void TopChanged(float value) - { - base.TopChanged(value); - Search_templates = false; - } - - public override void LeftChanged(float value) - { - base.LeftChanged(value); - Search_templates = false; - } - + [ObservableProperty] + bool export_ocr; [ObservableProperty] + string text_export_ocr; + + partial void OnExport_ocrChanged(bool value) + { + if (Export_ocr) + { + Text_export_ocr = ""; + if (!string.IsNullOrEmpty(Nombre) && _mainViewModel != null) + { + foreach (var objetoSimulable in _mainViewModel.ObjetosSimulables) + { + if (objetoSimulable != this && objetoSimulable.Group_Panel == Nombre) + { + if (objetoSimulable is osExtraccionTag osExtraccionTag) + { + osExtraccionTag.CaptureImageAreaAndDoOCR(); + Text_export_ocr += osExtraccionTag.Tag_extract; + } + } + } + } + } + Export_ocr = false; + } + + public override void TopChanging(float oldValue, float newValue) + { + UpdateChildsTop(newValue - oldValue); + } + public override void LeftChanging(float oldValue, float newValue) + { + UpdateChildsLeft(newValue - oldValue); + } + + [ObservableProperty] + [property: Description("Width of the object.")] + [property: Category("Position:")] public float ancho; - partial void OnAnchoChanged(float value) - { - Search_templates = false; - } - [ObservableProperty] + [property: Description("Height of the object.")] + [property: Category("Position:")] public float alto; - partial void OnAltoChanged(float value) - { - Search_templates = false; - } - - public override void OnTimerAfterMovement() - { - } - - [ObservableProperty] - public int n_Repeat_X; - - [ObservableProperty] - public int n_Repeat_Y; - - [ObservableProperty] - public float offset_Repeat_X; - - [ObservableProperty] - public float offset_Repeat_Y; - [ObservableProperty] public float angulo; @@ -117,12 +122,17 @@ namespace CtrEditor.ObjetosSim.Extraccion_Datos [ObservableProperty] float threshold; + [ObservableProperty] + float coincidencias; + + public osBuscarCoincidencias() { Ancho = 1; Alto = 1; Angulo = 0; Opacity_oculto = 0.1f; + Threshold = 0.6f; } private void ShowPreviewWindow(Stream imageStream) @@ -165,6 +175,7 @@ namespace CtrEditor.ObjetosSim.Extraccion_Datos } + private void BuscarCoincidenciasAsync(ProgressDialog progressDialog) { // Reset the Canvas children @@ -241,6 +252,14 @@ namespace CtrEditor.ObjetosSim.Extraccion_Datos int ConteoPositivos = 0; + // Lista para mantener áreas ya aceptadas + List acceptedRectangles = new List(); + + if (search_rectangles != null) + search_rectangles.Clear(); + else + search_rectangles = new List(); + // Obtener los puntos que superan el umbral float[] resultArray = result.GetData(false) as float[]; if (resultArray != null) @@ -251,24 +270,46 @@ namespace CtrEditor.ObjetosSim.Extraccion_Datos { int row = i / result.Cols; int col = i % result.Cols; - // Crear y agregar el rectángulo al Canvas (ajustando por la escala) + Rect newRect = new Rect(); + newRect.X = col / scaleFactorX; + newRect.Y = row / scaleFactorY; + newRect.Width = width / scaleFactorX; + newRect.Height = height / scaleFactorY; + + // Crear un rectángulo para la coincidencia actual Rectangle matchRect = new Rectangle { Stroke = new SolidColorBrush(Colors.Red), StrokeThickness = 2, - Width = width / scaleFactorX, - Height = height / scaleFactorY, + Width = newRect.Width, + Height = newRect.Height, Tag = "BuscarCoincidencias" }; - Canvas.SetLeft(matchRect, col / scaleFactorX); - Canvas.SetTop(matchRect, row / scaleFactorY); - Canvas.SetZIndex(matchRect, 40); - _mainViewModel.MainCanvas.Children.Add(matchRect); - ConteoPositivos++; - progressDialog.ReportProgress(90); - if (ConteoPositivos > 20) - return; + + Canvas.SetLeft(matchRect, newRect.X); + Canvas.SetTop(matchRect, newRect.Y); + + // Verificar si la coincidencia actual está dentro de algún rectángulo aceptado + bool isOverlap = acceptedRectangles.Any(r => + new Rect(Canvas.GetLeft(r), Canvas.GetTop(r), r.Width, r.Height).IntersectsWith( + new Rect(Canvas.GetLeft(matchRect), Canvas.GetTop(matchRect), matchRect.Width, matchRect.Height) + )); + + // Si no hay superposición, agregar el rectángulo al Canvas y a la lista de aceptados + if (!isOverlap) + { + Canvas.SetZIndex(matchRect, 40); + _mainViewModel.MainCanvas.Children.Add(matchRect); + acceptedRectangles.Add(matchRect); + search_rectangles.Add(newRect); + + ConteoPositivos++; + Coincidencias = ConteoPositivos; + progressDialog.ReportProgress(90); + if (ConteoPositivos > 20) + return; + } } } } @@ -277,6 +318,7 @@ namespace CtrEditor.ObjetosSim.Extraccion_Datos }); } + // Método para convertir BitmapSource a Mat private Mat BitmapSourceToMat(BitmapSource bitmapSource) { diff --git a/ObjetosSim/Extraccion Datos/ucExtraccionTag.xaml.cs b/ObjetosSim/Extraccion Datos/ucExtraccionTag.xaml.cs index b93c7d5..96ad9ed 100644 --- a/ObjetosSim/Extraccion Datos/ucExtraccionTag.xaml.cs +++ b/ObjetosSim/Extraccion Datos/ucExtraccionTag.xaml.cs @@ -1,15 +1,9 @@ using System.Windows; using System.Windows.Controls; -using System.Windows.Media.Animation; -using System.Windows.Media; +using System.Windows.Navigation; using CommunityToolkit.Mvvm.ComponentModel; - -using CtrEditor.Siemens; using CtrEditor.Simulacion; -using System.Windows.Input; -using System.IO; -using System.Windows.Media.Imaging; -using Tesseract; +using Newtonsoft.Json; namespace CtrEditor.ObjetosSim.Extraccion_Datos @@ -78,7 +72,7 @@ namespace CtrEditor.ObjetosSim.Extraccion_Datos } [ObservableProperty] - osBase search_Templates; + osBuscarCoincidencias search_Templates; [ObservableProperty] public float angulo; @@ -95,10 +89,6 @@ namespace CtrEditor.ObjetosSim.Extraccion_Datos [ObservableProperty] float opacity_oculto; - [ObservableProperty] - bool show_debug_ocr; - - public osExtraccionTag() { Ancho = 1; @@ -107,80 +97,9 @@ namespace CtrEditor.ObjetosSim.Extraccion_Datos Opacity_oculto = 0.1f; } - private void ShowPreviewWindow(Stream imageStream) + public void CaptureImageAreaAndDoOCR() { - // Create a new window for preview - Window previewWindow = new Window - { - Title = "Preview Captured Image", - Width = 500, - Height = 500, - Content = new Image - { - Source = BitmapFrame.Create(imageStream, BitmapCreateOptions.None, BitmapCacheOption.OnLoad), - Stretch = Stretch.Uniform - } - }; - - previewWindow.ShowDialog(); - } - - private void CaptureImageAreaAndDoOCR() - { - if (_mainViewModel?.MainCanvas.Children[0] is Image imagenDeFondo) - { - // Asegurarse de que la imagen origen está disponible - if (imagenDeFondo.Source is BitmapSource bitmapSource) - { - // Obtener los DPI de la imagen original - float originalDpiX = (float) bitmapSource.DpiX; - float originalDpiY = (float) bitmapSource.DpiY; - - // Estándar DPI en el que el Canvas renderiza la imagen - float canvasDpiX = 96; // WPF usually renders at 96 DPI - float canvasDpiY = 96; - - // Calcular el ratio de escala entre el Canvas y la imagen original - float scaleFactorX = originalDpiX / canvasDpiX; - float scaleFactorY = originalDpiY / canvasDpiY; - - // Ajustar las coordenadas de recorte en función del ratio de escala - int x = (int)MeterToPixels(Left * scaleFactorX); - int y = (int)MeterToPixels(Top * scaleFactorY); - int width = (int)MeterToPixels(Ancho * scaleFactorX); - int height = (int)MeterToPixels(Alto * scaleFactorY); - - // Validar y ajustar el tamaño del recorte para que se mantenga dentro de los límites de la imagen - if (x < 0) x = 0; - if (y < 0) y = 0; - if (x + width > bitmapSource.PixelWidth) width = bitmapSource.PixelWidth - x; - if (y + height > bitmapSource.PixelHeight) height = bitmapSource.PixelHeight - y; - - // Recortar el área deseada utilizando las coordenadas ajustadas - CroppedBitmap croppedBitmap = new CroppedBitmap(bitmapSource, new Int32Rect(x, y, width, height)); - - // Codificar el bitmap recortado a un MemoryStream - PngBitmapEncoder encoder = new PngBitmapEncoder(); - encoder.Frames.Add(BitmapFrame.Create(croppedBitmap)); - - using (MemoryStream memoryStream = new MemoryStream()) - { - encoder.Save(memoryStream); - memoryStream.Seek(0, SeekOrigin.Begin); - - // Mostrar la imagen recortada en una ventana de previsualización - if (show_debug_ocr) ShowPreviewWindow(memoryStream); - - // Cargar la imagen en Tesseract desde el MemoryStream - using (var img = Pix.LoadFromMemory(memoryStream.ToArray())) - using (var engine = new TesseractEngine(@"./Tesseract", "eng", EngineMode.Default)) - { - var result = engine.Process(img); - Tag_extract = result.GetText(); - } - } - } - } + Tag_extract = CaptureImageAreaAndDoOCR(Left, Top, Ancho, Alto); } public override void ucLoaded() diff --git a/ObjetosSim/UserControlFactory.cs b/ObjetosSim/UserControlFactory.cs index f0f235c..bb9bb8b 100644 --- a/ObjetosSim/UserControlFactory.cs +++ b/ObjetosSim/UserControlFactory.cs @@ -59,7 +59,9 @@ namespace CtrEditor.ObjetosSim } // Crear una instancia del tipo especificado - return (osBase?)Activator.CreateInstance(tipoObjeto); + osBase obj = (osBase?)Activator.CreateInstance(tipoObjeto); + obj.InicializaNuevoObjeto(); + return obj; } public static osBase? CreateInstanceAndPopulate(Type tipoObjeto, string jsonString) @@ -84,6 +86,14 @@ namespace CtrEditor.ObjetosSim } } + public static void LimpiarPropiedadesosDatos(PropertyGrid propertyGrid) + { + // Clear previous properties + propertyGrid.SelectedObject = null; + propertyGrid.PropertyDefinitions.Clear(); + } + + public static void CargarPropiedadesosDatos(object selectedObject, PropertyGrid propertyGrid) { // Clear previous properties @@ -114,7 +124,8 @@ namespace CtrEditor.ObjetosSim propertyDefinition.DisplayName = property.Name.Replace("_", " "); } if (property.PropertyType == typeof(double) || property.PropertyType == typeof(float) || property.PropertyType == typeof(string) || property.PropertyType == typeof(int) || - property.PropertyType == typeof(bool) || property.PropertyType == typeof(osBase) || property.PropertyType == typeof(Color) ) + property.PropertyType == typeof(bool) || property.PropertyType == typeof(osBase) || + property.PropertyType == typeof(osVMmotorSim) || property.PropertyType == typeof(osBuscarCoincidencias) || property.PropertyType == typeof(Color) ) { propertyGrid.PropertyDefinitions.Add(propertyDefinition); } diff --git a/ObjetosSim/UserControls/OSComboBox.xaml b/ObjetosSim/UserControls/OSComboBox.xaml new file mode 100644 index 0000000..e06d934 --- /dev/null +++ b/ObjetosSim/UserControls/OSComboBox.xaml @@ -0,0 +1,12 @@ + + + + + diff --git a/ObjetosSim/UserControls/OSComboBox.xaml.cs b/ObjetosSim/UserControls/OSComboBox.xaml.cs new file mode 100644 index 0000000..93ef0de --- /dev/null +++ b/ObjetosSim/UserControls/OSComboBox.xaml.cs @@ -0,0 +1,127 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.ComponentModel; +using System.Linq; +using System.Windows; +using System.Windows.Controls; + +namespace CtrEditor.ObjetosSim.UserControls +{ + public partial class OSComboBox : UserControl, INotifyPropertyChanged + { + public OSComboBox() + { + InitializeComponent(); + DataContext = this; + } + + public static readonly DependencyProperty ObjetosSimulablesProperty = + DependencyProperty.Register("ObjetosSimulables", typeof(IEnumerable), typeof(OSComboBox), new PropertyMetadata(null, OnObjetosSimulablesChanged)); + + public IEnumerable ObjetosSimulables + { + get { return (IEnumerable)GetValue(ObjetosSimulablesProperty); } + set { SetValue(ObjetosSimulablesProperty, value); } + } + + public static readonly DependencyProperty ObjectTypeProperty = + DependencyProperty.Register("ObjectType", typeof(Type), typeof(OSComboBox), new PropertyMetadata(null, OnObjectTypeChanged)); + + public Type ObjectType + { + get { return (Type)GetValue(ObjectTypeProperty); } + set { SetValue(ObjectTypeProperty, value); } + } + + public static readonly DependencyProperty SelectedObjectNameProperty = + DependencyProperty.Register("SelectedObjectName", typeof(string), typeof(OSComboBox), new PropertyMetadata(string.Empty, OnSelectedObjectNameChanged)); + + public string SelectedObjectName + { + get { + var str = (string)GetValue(SelectedObjectNameProperty); + return str; + } + set + { + SetValue(SelectedObjectNameProperty, value); + OnPropertyChanged(nameof(SelectedObjectName)); + } + } + + public static readonly DependencyProperty SelectedObjectProperty = + DependencyProperty.Register("SelectedObject", typeof(osBase), typeof(OSComboBox), new PropertyMetadata(null, OnSelectedObjectChanged)); + + public osBase SelectedObject + { + get { return (osBase)GetValue(SelectedObjectProperty); } + set + { + SetValue(SelectedObjectProperty, value); + OnPropertyChanged(nameof(SelectedObject)); + } + } + + public ObservableCollection FilteredObjetosSimulables { get; } = new ObservableCollection(); + + private static void OnObjetosSimulablesChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + var control = (OSComboBox)d; + control.FilterObjetosSimulables(); + } + + private static void OnObjectTypeChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + var control = (OSComboBox)d; + control.FilterObjetosSimulables(); + } + + private static void OnSelectedObjectNameChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + var control = (OSComboBox)d; + control.UpdateSelectedObject(); + } + + private static void OnSelectedObjectChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + var control = (OSComboBox)d; + control.UpdateSelectedObjectName(); + } + + private void FilterObjetosSimulables() + { + FilteredObjetosSimulables.Clear(); + if (ObjetosSimulables != null && ObjectType != null) + { + foreach (var obj in ObjetosSimulables.Where(o => o.GetType() == ObjectType)) + { + FilteredObjetosSimulables.Add(obj); + } + } + } + + private void UpdateSelectedObject() + { + if (SelectedObjectName != null && ObjetosSimulables != null) + { + SelectedObject = ObjetosSimulables.FirstOrDefault(o => o.Nombre == SelectedObjectName); + } + } + + private void UpdateSelectedObjectName() + { + if (SelectedObject != null) + { + SelectedObjectName = SelectedObject.Nombre; + } + } + + public event PropertyChangedEventHandler PropertyChanged; + + protected void OnPropertyChanged(string propertyName) + { + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); + } + } +} \ No newline at end of file diff --git a/ObjetosSim/osBase.cs b/ObjetosSim/osBase.cs index 7093965..b89638c 100644 --- a/ObjetosSim/osBase.cs +++ b/ObjetosSim/osBase.cs @@ -15,6 +15,13 @@ using System.Windows.Controls; using System.ComponentModel; using System.Configuration; using System.Windows.Threading; +using System.IO; +using Tesseract; +using Xceed.Wpf.Toolkit.PropertyGrid.Attributes; +using Newtonsoft.Json; +using JsonIgnoreAttribute = Newtonsoft.Json.JsonIgnoreAttribute; +using System.Collections.ObjectModel; +using ItemCollection = Xceed.Wpf.Toolkit.PropertyGrid.Attributes.ItemCollection; namespace CtrEditor.ObjetosSim { @@ -59,11 +66,17 @@ namespace CtrEditor.ObjetosSim public abstract partial class osBase : ObservableObject { public virtual string Nombre { get; set; } = "osBase"; + [JsonIgnore] private Storyboard _storyboard; + [JsonIgnore] private System.Threading.Timer timer = null; + public UniqueId Id { get; set; } + [ObservableProperty] + [property: Description("X coordinate.")] + [property: Category("Layout:")] private float left; partial void OnLeftChanged(float value) @@ -81,6 +94,8 @@ namespace CtrEditor.ObjetosSim public virtual void LeftChanging(float oldValue, float newValue) { } [ObservableProperty] + [property: Description("Y coordinate.")] + [property: Category("Layout:")] private float top; partial void OnTopChanged(float value) @@ -97,13 +112,128 @@ namespace CtrEditor.ObjetosSim public virtual void TopChanging(float oldValue, float newValue) { } - // Group + public void InicializaNuevoObjeto() + { + Id = new UniqueId().ObtenerNuevaID(); + } + + // Group [ObservableProperty] + [property: Description("This is a link to a faceplate. It works like an anchor.")] + [property: Category("Group:")] private string group_Panel; + protected void UpdateChildsTop(float offsetY) + { + if (!string.IsNullOrEmpty(Nombre) && _mainViewModel != null) + { + foreach (var objetoSimulable in _mainViewModel.ObjetosSimulables) + { + if (objetoSimulable != this && objetoSimulable.Group_Panel == Nombre) + { + objetoSimulable.Top += offsetY; + } + } + } + } + protected void UpdateChildsLeft(float offsetX) + { + if (!string.IsNullOrEmpty(Nombre) && _mainViewModel != null) + { + foreach (var objetoSimulable in _mainViewModel.ObjetosSimulables) + { + if (objetoSimulable != this && objetoSimulable.Group_Panel == Nombre) + { + objetoSimulable.Left += offsetX; + } + } + } + } + + private void ShowPreviewWindow(Stream imageStream) + { + // Create a new window for preview + Window previewWindow = new Window + { + Title = "Preview Captured Image", + Width = 500, + Height = 500, + Content = new Image + { + Source = BitmapFrame.Create(imageStream, BitmapCreateOptions.None, BitmapCacheOption.OnLoad), + Stretch = Stretch.Uniform + } + }; + + previewWindow.ShowDialog(); + } + + + public string CaptureImageAreaAndDoOCR(float Left, float Top, float Ancho, float Alto) + { + if (_mainViewModel?.MainCanvas.Children[0] is Image imagenDeFondo) + { + // Asegurarse de que la imagen origen está disponible + if (imagenDeFondo.Source is BitmapSource bitmapSource) + { + // Obtener los DPI de la imagen original + float originalDpiX = (float)bitmapSource.DpiX; + float originalDpiY = (float)bitmapSource.DpiY; + + // Estándar DPI en el que el Canvas renderiza la imagen + float canvasDpiX = 96; // WPF usually renders at 96 DPI + float canvasDpiY = 96; + + // Calcular el ratio de escala entre el Canvas y la imagen original + float scaleFactorX = originalDpiX / canvasDpiX; + float scaleFactorY = originalDpiY / canvasDpiY; + + // Ajustar las coordenadas de recorte en función del ratio de escala + int x = (int)MeterToPixels(Left * scaleFactorX); + int y = (int)MeterToPixels(Top * scaleFactorY); + int width = (int)MeterToPixels(Ancho * scaleFactorX); + int height = (int)MeterToPixels(Alto * scaleFactorY); + + // Validar y ajustar el tamaño del recorte para que se mantenga dentro de los límites de la imagen + if (x < 0) x = 0; + if (y < 0) y = 0; + if (x + width > bitmapSource.PixelWidth) width = bitmapSource.PixelWidth - x; + if (y + height > bitmapSource.PixelHeight) height = bitmapSource.PixelHeight - y; + + // Recortar el área deseada utilizando las coordenadas ajustadas + CroppedBitmap croppedBitmap = new CroppedBitmap(bitmapSource, new Int32Rect(x, y, width, height)); + + // Codificar el bitmap recortado a un MemoryStream + PngBitmapEncoder encoder = new PngBitmapEncoder(); + encoder.Frames.Add(BitmapFrame.Create(croppedBitmap)); + + using (MemoryStream memoryStream = new MemoryStream()) + { + encoder.Save(memoryStream); + memoryStream.Seek(0, SeekOrigin.Begin); + + //ShowPreviewWindow(memoryStream); + + // Cargar la imagen en Tesseract desde el MemoryStream + using (var img = Pix.LoadFromMemory(memoryStream.ToArray())) + using (var engine = new TesseractEngine(@"./Tesseract", "eng", EngineMode.Default)) + { + var result = engine.Process(img); + return result.GetText(); + } + } + } + } + return ""; + } + + + // All Pages Objects [NotifyPropertyChangedFor(nameof(Show_on_this_page))] [ObservableProperty] + [property: Description("Enable this object to be used in all pages.")] + [property: Category("Layout:")] private bool enable_on_all_pages; partial void OnEnable_on_all_pagesChanged(bool value) @@ -115,6 +245,7 @@ namespace CtrEditor.ObjetosSim private List Show_on_this_pages_oculto; private bool show_on_this_page; + [property: Category("Layout:")] public bool Show_on_this_page { get @@ -687,6 +818,45 @@ namespace CtrEditor.ObjetosSim } + public class UniqueId + { + public int Value { get; set; } + public UniqueId ObtenerNuevaID() + { + Value = EstadoPersistente.Instance.newid; + if (Value == 0) + Value++; + return this; + } + public void NoId() + { + // No ID == NULL + Value = 0; + } + } + + public class osBaseItemsSource : IItemsSource + { + public ItemCollection GetValues() + { + ItemCollection items = new ItemCollection(); + + var viewModel = (MainViewModel)App.Current.MainWindow.DataContext; + var objetosSimulables = viewModel.ObjetosSimulables; + + items.Add(""); + foreach (var obj in objetosSimulables) + { + if (obj.GetType() == typeof(T)) + { + items.Add(obj.Nombre); + } + } + + return items; + } + } + public class TimerTON_TOFF { Stopwatch _stopwatch_ON = new Stopwatch(); diff --git a/XAMLhelpers.cs b/XAMLhelpers.cs index 127fcc2..7c7b9a0 100644 --- a/XAMLhelpers.cs +++ b/XAMLhelpers.cs @@ -13,7 +13,6 @@ using System.Collections.ObjectModel; namespace CtrEditor { - public class SubclassFilterConverter : IValueConverter { public Type TargetType { get; set; } diff --git a/estadoPersistente.cs b/estadoPersistente.cs index 1f54424..86269fe 100644 --- a/estadoPersistente.cs +++ b/estadoPersistente.cs @@ -6,6 +6,7 @@ using System.Threading.Tasks; using System; using System.IO; using System.Text.Json; +using System.Security.Permissions; namespace CtrEditor { @@ -20,6 +21,9 @@ namespace CtrEditor // Propiedad privada para el directorio de trabajo private string _strDirectorioTrabajo; + private string _imagen; + private int _id; + // Propiedad pública con get y set para controlar el acceso a _strDirectorioTrabajo public string directorio { @@ -27,6 +31,20 @@ namespace CtrEditor set { _strDirectorioTrabajo = value; } } + public string imagen + { + get { return _imagen; } + set { _imagen = value; } + } + + public int newid + { + get { + _id++; + return _id; } + set { _id = value; } + } + // Constructor privado para evitar la instanciación externa public EstadoPersistente() {