diff --git a/MainViewModel.cs b/MainViewModel.cs index c5ba0b5..2cfd8fb 100644 --- a/MainViewModel.cs +++ b/MainViewModel.cs @@ -1,33 +1,21 @@ -using CtrEditor; -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Linq; +using System.ComponentModel; using System.Runtime.CompilerServices; -using System.Text; -using System.Threading.Tasks; using System.Windows.Controls; using System.Windows.Input; using Ookii.Dialogs.Wpf; using System.Collections.ObjectModel; using System.Windows.Media; -using System.Windows.Media.Imaging; -using static System.Runtime.InteropServices.JavaScript.JSType; using System.Windows.Threading; using CtrEditor.ObjetosSim; using CtrEditor.Siemens; using System.IO; // using System.Windows.Forms; -using System.Text.Json.Serialization; -using System.Text.Json; using Newtonsoft.Json; using System.Windows.Data; using System.Windows; -using static System.Resources.ResXFileRef; using CtrEditor.Convertidores; using CtrEditor.Simulacion; using System.Diagnostics; -using Newtonsoft.Json.Linq; using System.Reflection; namespace CtrEditor @@ -455,12 +443,16 @@ namespace CtrEditor private void ConnectPLC() { plcViewModelData.Connect(); + } private void DisconnectPLC() { plcViewModelData.Disconnect(); IsConnected = false; + foreach (var objetoSimulable in ObjetosSimulables) + objetoSimulable.SetPLC(null); + } private void OnRefreshEvent(object sender, EventArgs e) @@ -468,7 +460,12 @@ namespace CtrEditor if (plcViewModelData.IsConnected) { if (!isConnected) + { IsConnected = true; + foreach (var objetoSimulable in ObjetosSimulables) + objetoSimulable.SetPLC(plcViewModelData.PLCInterface); + + } // Detener el cronómetro y obtener el tiempo transcurrido en milisegundos stopwatch_PLCRefresh.Stop(); float elapsedMilliseconds = (float)stopwatch_PLCRefresh.Elapsed.TotalMilliseconds; @@ -599,133 +596,9 @@ namespace CtrEditor // Se cargan los datos de cada UserControl en el StackPanel public void CargarPropiedadesosDatos(osBase selectedObject, StackPanel PanelEdicion, ResourceDictionary Resources) { - PanelEdicion.Children.Clear(); - var properties = selectedObject.GetType().GetProperties(); - - foreach (var property in properties) - { - if (Attribute.IsDefined(property, typeof(HiddenAttribute))) - continue; - if (property.Name.EndsWith("_oculto")) - continue; - - var grid = new Grid(); - grid.ColumnDefinitions.Add(new ColumnDefinition { Width = GridLength.Auto }); - grid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(1, GridUnitType.Star) }); - - var label = new Label - { - Content = property.Name.Replace("_", " ") + ":", - Margin = new Thickness(0, 0, 5, 0), - VerticalAlignment = VerticalAlignment.Center - }; - - if (property.PropertyType == typeof(float) || property.PropertyType == typeof(string) || property.PropertyType == typeof(int)) - { - var textBox = new TextBox - { - Margin = new Thickness(0), - MinWidth = 200, - VerticalContentAlignment = VerticalAlignment.Center - }; - - var binding = new Binding(property.Name) - { - Source = selectedObject, - Mode = BindingMode.TwoWay, - UpdateSourceTrigger = UpdateSourceTrigger.LostFocus - }; - - if (property.PropertyType == typeof(float)) - { - binding.Converter = (FloatToFormattedStringConverter)Resources["floatFormatter"]; - } - - textBox.SetBinding(TextBox.TextProperty, binding); - - Grid.SetColumn(label, 0); - Grid.SetColumn(textBox, 1); - - grid.Children.Add(label); - grid.Children.Add(textBox); - } - else if (property.PropertyType == typeof(bool)) - { - var checkBox = new CheckBox - { - Margin = new Thickness(5, 0, 0, 0), - VerticalAlignment = VerticalAlignment.Center - }; - - var binding = new Binding(property.Name) - { - Source = selectedObject, - Mode = BindingMode.TwoWay - }; - - checkBox.SetBinding(CheckBox.IsCheckedProperty, binding); - - Grid.SetColumn(label, 0); - Grid.SetColumn(checkBox, 1); - - grid.Children.Add(label); - grid.Children.Add(checkBox); - } - else if (property.PropertyType == typeof(Brush)) - { - var listBox = new ListBox - { - ItemsSource = new List { "Rojo", "Azul", "Negro", "Verde", "Gris" }, - Margin = new Thickness(0), - MinWidth = 200 - }; - - listBox.SelectionChanged += (sender, e) => - { - if (listBox.SelectedItem != null) - { - switch (listBox.SelectedItem.ToString()) - { - case "Rojo": - property.SetValue(selectedObject, Brushes.Red); - break; - case "Azul": - property.SetValue(selectedObject, Brushes.Blue); - break; - case "Negro": - property.SetValue(selectedObject, Brushes.Black); - break; - case "Verde": - property.SetValue(selectedObject, Brushes.Green); - break; - case "Gris": - property.SetValue(selectedObject, Brushes.Gray); - break; - } - } - }; - - var binding = new Binding(property.Name) - { - Source = selectedObject, - Mode = BindingMode.TwoWay, - Converter = new BrushToColorNameConverter() - }; - - listBox.SetBinding(ListBox.SelectedItemProperty, binding); - - Grid.SetColumn(label, 0); - Grid.SetColumn(listBox, 1); - - grid.Children.Add(label); - grid.Children.Add(listBox); - } - - PanelEdicion.Children.Add(grid); - } + UserControlFactory.CargarPropiedadesosDatos(selectedObject,PanelEdicion, Resources); } - // Implementación de INotifyPropertyChanged... public event PropertyChangedEventHandler PropertyChanged; diff --git a/MainWindow.xaml b/MainWindow.xaml index 1013a61..671819d 100644 --- a/MainWindow.xaml +++ b/MainWindow.xaml @@ -121,7 +121,7 @@ - + diff --git a/ObjetosSim/UserControlFactory.cs b/ObjetosSim/UserControlFactory.cs index 0d48e62..358a4db 100644 --- a/ObjetosSim/UserControlFactory.cs +++ b/ObjetosSim/UserControlFactory.cs @@ -1,12 +1,13 @@ using Newtonsoft.Json; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; using System.Windows.Controls; using CtrEditor.Simulacion; using System.Reflection; +using CtrEditor.Convertidores; +using System.Windows.Data; +using System.Windows; +using System.Windows.Media; +using CtrEditor.ObjetosSim.UserControls; +using System.Collections; namespace CtrEditor.ObjetosSim { @@ -73,7 +74,278 @@ namespace CtrEditor.ObjetosSim datos.simulationManager = simulationManager; } } + + + public static void CargarPropiedadesosDatos(Object selectedObject, StackPanel PanelEdicion, ResourceDictionary Resources) + { + PanelEdicion.Children.Clear(); + var properties = selectedObject.GetType().GetProperties(); + + foreach (var property in properties) + { + if (Attribute.IsDefined(property, typeof(HiddenAttribute))) + continue; + if (property.Name.EndsWith("_oculto")) + continue; + + var grid = new Grid(); + grid.ColumnDefinitions.Add(new ColumnDefinition { Width = GridLength.Auto }); + grid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(1, GridUnitType.Star) }); + + var label = new Label + { + Content = property.Name.Replace("_", " ") + ":", + Margin = new Thickness(0, 0, 5, 0), + VerticalAlignment = VerticalAlignment.Center + }; + + Grid.SetColumn(label, 0); + grid.Children.Add(label); + + if (property.PropertyType == typeof(float) || property.PropertyType == typeof(string) || property.PropertyType == typeof(int)) + { + var textBox = new TextBox + { + Margin = new Thickness(0), + MinWidth = 200, + VerticalContentAlignment = VerticalAlignment.Center + }; + + var binding = new Binding(property.Name) + { + Source = selectedObject, + Mode = BindingMode.TwoWay, + UpdateSourceTrigger = UpdateSourceTrigger.LostFocus + }; + + if (property.PropertyType == typeof(float)) + { + if (Resources != null) + binding.Converter = (FloatToFormattedStringConverter)Resources["floatFormatter"]; + } + + textBox.SetBinding(TextBox.TextProperty, binding); + + Grid.SetColumn(textBox, 1); + grid.Children.Add(textBox); + } + else if (property.PropertyType == typeof(bool)) + { + var checkBox = new CheckBox + { + Margin = new Thickness(5, 0, 0, 0), + VerticalAlignment = VerticalAlignment.Center + }; + + var binding = new Binding(property.Name) + { + Source = selectedObject, + Mode = BindingMode.TwoWay + }; + + checkBox.SetBinding(CheckBox.IsCheckedProperty, binding); + + Grid.SetColumn(checkBox, 1); + grid.Children.Add(checkBox); + } + else if (property.PropertyType == typeof(Brush)) + { + var listBox = new ListBox + { + ItemsSource = new List { "Rojo", "Azul", "Negro", "Verde", "Gris" }, + Margin = new Thickness(0), + MinWidth = 200 + }; + + listBox.SelectionChanged += (sender, e) => + { + if (listBox.SelectedItem != null) + { + switch (listBox.SelectedItem.ToString()) + { + case "Rojo": + property.SetValue(selectedObject, Brushes.Red); + break; + case "Azul": + property.SetValue(selectedObject, Brushes.Blue); + break; + case "Negro": + property.SetValue(selectedObject, Brushes.Black); + break; + case "Verde": + property.SetValue(selectedObject, Brushes.Green); + break; + case "Gris": + property.SetValue(selectedObject, Brushes.Gray); + break; + } + } + }; + + var binding = new Binding(property.Name) + { + Source = selectedObject, + Mode = BindingMode.TwoWay, + Converter = new BrushToColorNameConverter() + }; + + listBox.SetBinding(ListBox.SelectedItemProperty, binding); + + Grid.SetColumn(listBox, 1); + grid.Children.Add(listBox); + } + PanelEdicion.Children.Add(grid); + } + } + + public static List CargarPropiedadesosDatosTags(Object selectedObject, StackPanel PanelEdicion, ResourceDictionary Resources) + { + PanelEdicion.Children.Clear(); + var properties = selectedObject.GetType().GetProperties(); + List tags = new List(); + + foreach (var property in properties) + { + if (Attribute.IsDefined(property, typeof(HiddenAttribute))) + continue; + if (property.Name.EndsWith("_oculto")) + continue; + + var grid = new Grid(); + grid.ColumnDefinitions.Add(new ColumnDefinition { Width = GridLength.Auto }); + grid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(1, GridUnitType.Star) }); + grid.ColumnDefinitions.Add(new ColumnDefinition { Width = GridLength.Auto }); + + var label = new Label + { + Content = property.Name.Replace("_", " ") + ":", + Margin = new Thickness(0, 0, 5, 0), + VerticalAlignment = VerticalAlignment.Center + }; + + Grid.SetColumn(label, 0); + grid.Children.Add(label); + + if (property.PropertyType == typeof(float) || property.PropertyType == typeof(string) || property.PropertyType == typeof(int)) + { + var textBox = new TextBox + { + Margin = new Thickness(0), + MinWidth = 200, + VerticalContentAlignment = VerticalAlignment.Center + }; + + var binding = new Binding(property.Name) + { + Source = selectedObject, + Mode = BindingMode.TwoWay, + UpdateSourceTrigger = UpdateSourceTrigger.LostFocus + }; + + if (property.PropertyType == typeof(float)) + { + if (Resources != null) + binding.Converter = (FloatToFormattedStringConverter)Resources["floatFormatter"]; + } + + textBox.SetBinding(TextBox.TextProperty, binding); + + Grid.SetColumn(textBox, 1); + grid.Children.Add(textBox); + + var tagTextBox = new TextBox + { + Margin = new Thickness(0), + MinWidth = 100, + VerticalContentAlignment = VerticalAlignment.Center + }; + + // Add an empty string to the tags list and get the index + tags.Add(string.Empty); + int tagIndex = tags.Count - 1; + + // Event handler to update the tags list when the text changes + tagTextBox.TextChanged += (sender, args) => + { + tags[tagIndex] = tagTextBox.Text; + }; + + Grid.SetColumn(tagTextBox, 2); + grid.Children.Add(tagTextBox); + } + else if (property.PropertyType == typeof(bool)) + { + var checkBox = new CheckBox + { + Margin = new Thickness(5, 0, 0, 0), + VerticalAlignment = VerticalAlignment.Center + }; + + var binding = new Binding(property.Name) + { + Source = selectedObject, + Mode = BindingMode.TwoWay + }; + + checkBox.SetBinding(CheckBox.IsCheckedProperty, binding); + + Grid.SetColumn(checkBox, 1); + grid.Children.Add(checkBox); + } + else if (property.PropertyType == typeof(Brush)) + { + var listBox = new ListBox + { + ItemsSource = new List { "Rojo", "Azul", "Negro", "Verde", "Gris" }, + Margin = new Thickness(0), + MinWidth = 200 + }; + + listBox.SelectionChanged += (sender, e) => + { + if (listBox.SelectedItem != null) + { + switch (listBox.SelectedItem.ToString()) + { + case "Rojo": + property.SetValue(selectedObject, Brushes.Red); + break; + case "Azul": + property.SetValue(selectedObject, Brushes.Blue); + break; + case "Negro": + property.SetValue(selectedObject, Brushes.Black); + break; + case "Verde": + property.SetValue(selectedObject, Brushes.Green); + break; + case "Gris": + property.SetValue(selectedObject, Brushes.Gray); + break; + } + } + }; + + var binding = new Binding(property.Name) + { + Source = selectedObject, + Mode = BindingMode.TwoWay, + Converter = new BrushToColorNameConverter() + }; + + listBox.SetBinding(ListBox.SelectedItemProperty, binding); + + Grid.SetColumn(listBox, 1); + grid.Children.Add(listBox); + } + + PanelEdicion.Children.Add(grid); + } + + return tags; + } + } - } + diff --git a/ObjetosSim/UserControls/GearControl.xaml b/ObjetosSim/UserControls/GearControl.xaml new file mode 100644 index 0000000..9a1ce0c --- /dev/null +++ b/ObjetosSim/UserControls/GearControl.xaml @@ -0,0 +1,11 @@ + + + + + diff --git a/ObjetosSim/UserControls/GearControl.xaml.cs b/ObjetosSim/UserControls/GearControl.xaml.cs new file mode 100644 index 0000000..c67d6d9 --- /dev/null +++ b/ObjetosSim/UserControls/GearControl.xaml.cs @@ -0,0 +1,120 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Navigation; +using System.Windows.Shapes; + +namespace CtrEditor.ObjetosSim.UserControls +{ + /// + /// Interaction logic for GearControl.xaml + /// + public partial class GearControl : UserControl + { + public static readonly DependencyProperty TeethCountProperty = + DependencyProperty.Register("TeethCount", typeof(int), typeof(GearControl), + new PropertyMetadata(10, OnGearPropertyChanged)); + + public static readonly DependencyProperty InnerRadiusProperty = + DependencyProperty.Register("InnerRadius", typeof(double), typeof(GearControl), + new PropertyMetadata(40.0, OnGearPropertyChanged)); + + public static readonly DependencyProperty OuterRadiusProperty = + DependencyProperty.Register("OuterRadius", typeof(double), typeof(GearControl), + new PropertyMetadata(60.0, OnGearPropertyChanged)); + + public static readonly DependencyProperty ToothWidthRatioProperty = + DependencyProperty.Register("ToothWidthRatio", typeof(double), typeof(GearControl), + new PropertyMetadata(0.5, OnGearPropertyChanged)); + + public int TeethCount + { + get { return (int)GetValue(TeethCountProperty); } + set { SetValue(TeethCountProperty, value); } + } + + public double InnerRadius + { + get { return (double)GetValue(InnerRadiusProperty); } + set { SetValue(InnerRadiusProperty, value); } + } + + public double OuterRadius + { + get { return (double)GetValue(OuterRadiusProperty); } + set { SetValue(OuterRadiusProperty, value); } + } + + public double ToothWidthRatio + { + get { return (double)GetValue(ToothWidthRatioProperty); } + set { SetValue(ToothWidthRatioProperty, value); } + } + + public GearControl() + { + InitializeComponent(); + DrawGear(); + } + + private static void OnGearPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + var control = d as GearControl; + control?.DrawGear(); + } + + private void DrawGear() + { + GearCanvas.Children.Clear(); + double centerX = ActualWidth / 2; + double centerY = ActualHeight / 2; + double angleStep = 360.0 / TeethCount; + double toothWidthAngle = angleStep * ToothWidthRatio; + + // Draw inner circle + Ellipse innerCircle = new Ellipse + { + Width = InnerRadius * 2, + Height = InnerRadius * 2, + Stroke = Brushes.Black, + StrokeThickness = 2, + Fill = Brushes.Gray + }; + + Canvas.SetLeft(innerCircle, centerX - InnerRadius); + Canvas.SetTop(innerCircle, centerY - InnerRadius); + GearCanvas.Children.Add(innerCircle); + + for (int i = 0; i < TeethCount; i++) + { + double angle = i * angleStep; + double radianStart = (angle - toothWidthAngle / 2) * Math.PI / 180; + double radianEnd = (angle + toothWidthAngle / 2) * Math.PI / 180; + + Point p1 = new Point(centerX + InnerRadius * Math.Cos(radianStart), centerY + InnerRadius * Math.Sin(radianStart)); + Point p2 = new Point(centerX + OuterRadius * Math.Cos(radianStart), centerY + OuterRadius * Math.Sin(radianStart)); + Point p3 = new Point(centerX + OuterRadius * Math.Cos(radianEnd), centerY + OuterRadius * Math.Sin(radianEnd)); + Point p4 = new Point(centerX + InnerRadius * Math.Cos(radianEnd), centerY + InnerRadius * Math.Sin(radianEnd)); + + Polygon tooth = new Polygon + { + Stroke = Brushes.Black, + StrokeThickness = 2, + Fill = Brushes.LightGray, + Points = new PointCollection { p1, p2, p3, p4 } + }; + + GearCanvas.Children.Add(tooth); + } + } + } +} diff --git a/ObjetosSim/UserControls/ucAnalogTag.xaml b/ObjetosSim/UserControls/ucAnalogTag.xaml new file mode 100644 index 0000000..5ad741e --- /dev/null +++ b/ObjetosSim/UserControls/ucAnalogTag.xaml @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/ObjetosSim/UserControls/ucAnalogTag.xaml.cs b/ObjetosSim/UserControls/ucAnalogTag.xaml.cs new file mode 100644 index 0000000..46bb29e --- /dev/null +++ b/ObjetosSim/UserControls/ucAnalogTag.xaml.cs @@ -0,0 +1,124 @@ +using CtrEditor.Convertidores; +using CtrEditor.Siemens; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Media; +using CommunityToolkit.Mvvm.ComponentModel; +using Newtonsoft.Json.Linq; + +namespace CtrEditor.ObjetosSim.UserControls +{ + /// + /// Interaction logic for ucAnalogTag.xaml + /// + /// + + public partial class osAnalogTag : osBase, IosBase + { + + // Otros datos y métodos relevantes para la simulación + + public static string NombreClase() + { + return "Analog Tag"; + } + private string nombre = NombreClase(); + public override string Nombre + { + get => nombre; + set => SetProperty(ref nombre, value); + } + + [ObservableProperty] + public float tamano; + [ObservableProperty] + public string tag; + [ObservableProperty] + public string descripcion; + [ObservableProperty] + public float min_IN_Scaled; + [ObservableProperty] + public float max_IN_Scaled; + [ObservableProperty] + public float min_OUT_Scaled; + [ObservableProperty] + public float max_OUT_Scaled; + [ObservableProperty] + public float value; + + partial void OnValueChanged(float value) + { + EscribirWordTagScaled(Tag, Value, Min_IN_Scaled, Max_IN_Scaled, Min_OUT_Scaled, Max_OUT_Scaled); + } + + public osAnalogTag() + { + Tamano = 0.30f; + tag = "%MW50.0"; + Descripcion = "Nombre del Tag:"; + Max_OUT_Scaled = 27648; + Min_OUT_Scaled = 0; + min_IN_Scaled = 0; + max_IN_Scaled = 100; + + } + + public override void UpdateGeometryStart() + { + // Se llama antes de la simulacion + + } + public override void UpdatePLC(PLCModel plc, int elapsedMilliseconds) + { + } + + public override void UpdateControl(int elapsedMilliseconds) + { + // Calculamos la velocidad + + } + + public override void ucLoaded() + { + // El UserControl ya se ha cargado y podemos obtener las coordenadas para + // crear el objeto de simulacion + ActualizarLeftTop(); + + } + } + + public partial class ucAnalogTag : UserControl, IDataContainer + { + public osBase? Datos { get; set; } + + public ucAnalogTag() + { + InitializeComponent(); + this.Loaded += OnLoaded; + this.Unloaded += OnUnloaded; + } + private void OnLoaded(object sender, RoutedEventArgs e) + { + Datos?.ucLoaded(); + } + private void OnUnloaded(object sender, RoutedEventArgs e) + { + Datos?.ucUnLoaded(); + } + public void Resize(float width, float height) { } + public void Move(float LeftPixels, float TopPixels) + { + if (Datos != null) + { + Datos.Left = PixelToMeter.Instance.calc.PixelsToMeters(LeftPixels); + Datos.Top = PixelToMeter.Instance.calc.PixelsToMeters(TopPixels); + } + } + public void Rotate(float Angle) { } + public void Highlight(bool State) { } + public int ZIndex() + { + return 10; + } + } +} diff --git a/ObjetosSim/UserControls/ucBoolTag.xaml b/ObjetosSim/UserControls/ucBoolTag.xaml new file mode 100644 index 0000000..2eedc65 --- /dev/null +++ b/ObjetosSim/UserControls/ucBoolTag.xaml @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + diff --git a/ObjetosSim/UserControls/ucBoolTag.xaml.cs b/ObjetosSim/UserControls/ucBoolTag.xaml.cs new file mode 100644 index 0000000..35b2e9c --- /dev/null +++ b/ObjetosSim/UserControls/ucBoolTag.xaml.cs @@ -0,0 +1,118 @@ +using CtrEditor.Convertidores; +using CtrEditor.Siemens; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Media; +using CommunityToolkit.Mvvm.ComponentModel; + +namespace CtrEditor.ObjetosSim.UserControls +{ + /// + /// Interaction logic for ucBoolTag.xaml + /// + /// + + public partial class osBoolTag : osBase, IosBase + { + + // Otros datos y métodos relevantes para la simulación + + public static string NombreClase() + { + return "Bool Tag"; + } + private string nombre = NombreClase(); + public override string Nombre + { + get => nombre; + set => SetProperty(ref nombre, value); + } + + [ObservableProperty] + private Brush color_oculto; + + partial void OnEstadoChanged(bool value) + { + if (value) + Color_oculto = Brushes.LightGreen; + else + Color_oculto = Brushes.Transparent; + } + + [ObservableProperty] + public float tamano; + [ObservableProperty] + public string tag; + [ObservableProperty] + public string descripcion; + [ObservableProperty] + public bool estado; + + + public osBoolTag() + { + Tamano = 0.30f; + tag = "%M50.0"; + Descripcion = "Nombre del Tag"; + } + + public override void UpdateGeometryStart() + { + // Se llama antes de la simulacion + + } + public override void UpdatePLC(PLCModel plc, int elapsedMilliseconds) + { + plc.EscribirTagBool(Tag, Estado); + } + + public override void UpdateControl(int elapsedMilliseconds) + { + // Calculamos la velocidad + + } + + public override void ucLoaded() + { + // El UserControl ya se ha cargado y podemos obtener las coordenadas para + // crear el objeto de simulacion + ActualizarLeftTop(); + + } + } + + public partial class ucBoolTag : UserControl, IDataContainer + { + public osBase? Datos { get; set; } + + public ucBoolTag() + { + InitializeComponent(); + this.Loaded += OnLoaded; + this.Unloaded += OnUnloaded; + } + private void OnLoaded(object sender, RoutedEventArgs e) + { + Datos?.ucLoaded(); + } + private void OnUnloaded(object sender, RoutedEventArgs e) + { + Datos?.ucUnLoaded(); + } + public void Resize(float width, float height) { } + public void Move(float LeftPixels, float TopPixels) + { + if (Datos != null) + { + Datos.Left = PixelToMeter.Instance.calc.PixelsToMeters(LeftPixels); + Datos.Top = PixelToMeter.Instance.calc.PixelsToMeters(TopPixels); + } + } + public void Rotate(float Angle) { } + public void Highlight(bool State) { } + public int ZIndex() + { + return 10; + } + } +} diff --git a/ObjetosSim/UserControls/ucBoton.xaml.cs b/ObjetosSim/UserControls/ucBoton.xaml.cs index 16392d0..0462d80 100644 --- a/ObjetosSim/UserControls/ucBoton.xaml.cs +++ b/ObjetosSim/UserControls/ucBoton.xaml.cs @@ -26,6 +26,8 @@ namespace CtrEditor.ObjetosSim set => SetProperty(ref nombre, value); } + [ObservableProperty] + public bool tipo_NC; [ObservableProperty] private Brush color; [ObservableProperty] @@ -41,6 +43,10 @@ namespace CtrEditor.ObjetosSim ColorButton_oculto = Brushes.LightGreen; else ColorButton_oculto = Color; + if (!tipo_NC) + EscribirBitTag(Tag, value); + else + EscribirBitTag(Tag, !value); } [ObservableProperty] @@ -71,7 +77,7 @@ namespace CtrEditor.ObjetosSim } public override void UpdatePLC(PLCModel plc, int elapsedMilliseconds) { - plc.EscribirTagBool(Tag, Estado); + } public override void UpdateControl(int elapsedMilliseconds) diff --git a/ObjetosSim/UserControls/ucConsensGeneric.xaml b/ObjetosSim/UserControls/ucConsensGeneric.xaml new file mode 100644 index 0000000..f538f53 --- /dev/null +++ b/ObjetosSim/UserControls/ucConsensGeneric.xaml @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + diff --git a/ObjetosSim/UserControls/ucConsensGeneric.xaml.cs b/ObjetosSim/UserControls/ucConsensGeneric.xaml.cs new file mode 100644 index 0000000..b86479b --- /dev/null +++ b/ObjetosSim/UserControls/ucConsensGeneric.xaml.cs @@ -0,0 +1,92 @@ +using CommunityToolkit.Mvvm.ComponentModel; +using CtrEditor.Convertidores; +using CtrEditor.Siemens; +using System.Windows; +using System.Windows.Controls; + + +namespace CtrEditor.ObjetosSim.UserControls +{ + /// + /// Interaction logic for ucConsensGeneric.xaml + /// + public partial class osConsensGeneric : osBase, IosBase + { + + public TagsConsensos Consensos = new TagsConsensos(); + + [ObservableProperty] + public List tags; + + // Otros datos y métodos relevantes para la simulación + + public static string NombreClase() + { + return "Consensi"; + } + private string nombre = NombreClase(); + public override string Nombre + { + get => nombre; + set => SetProperty(ref nombre, value); + } + + [ObservableProperty] + public float tamano; + + public override void ucLoaded() + { + // El UserControl ya se ha cargado y podemos obtener las coordenadas para + // crear el objeto de simulacion + ActualizarLeftTop(); + + if (_visualRepresentation is ucConsensGeneric uc) + Tags = UserControlFactory.CargarPropiedadesosDatosTags(Consensos, uc.PanelEdicion, null); + + } + } + + public partial class ucConsensGeneric : UserControl, IDataContainer + { + public osBase? Datos { get; set; } + + public ucConsensGeneric() + { + InitializeComponent(); + this.Loaded += OnLoaded; + this.Unloaded += OnUnloaded; + } + private void OnLoaded(object sender, RoutedEventArgs e) + { + Datos?.ucLoaded(); + } + private void OnUnloaded(object sender, RoutedEventArgs e) + { + Datos?.ucUnLoaded(); + } + public void Resize(float width, float height) { } + public void Move(float LeftPixels, float TopPixels) + { + if (Datos != null) + { + Datos.Left = PixelToMeter.Instance.calc.PixelsToMeters(LeftPixels); + Datos.Top = PixelToMeter.Instance.calc.PixelsToMeters(TopPixels); + } + } + public void Rotate(float Angle) { } + public void Highlight(bool State) { } + public int ZIndex() + { + return 10; + } + } + + public class TagsConsensos + { + public string Tag { get; set; } + public bool Consenso_Uscita { get; set; } + public string Velocidad { get; set; } + } + +} + diff --git a/ObjetosSim/UserControls/ucFiller.xaml.cs b/ObjetosSim/UserControls/ucFiller.xaml.cs index c7dcb4d..cd2804b 100644 --- a/ObjetosSim/UserControls/ucFiller.xaml.cs +++ b/ObjetosSim/UserControls/ucFiller.xaml.cs @@ -60,7 +60,7 @@ namespace CtrEditor.ObjetosSim public override void UpdatePLC(PLCModel plc, int elapsedMilliseconds) { - Consenso = LeerBitTag(plc, Tag_consenso); + Consenso = LeerBitTag(Tag_consenso); } public override void UpdateControl(int elapsedMilliseconds) diff --git a/ObjetosSim/UserControls/ucGearEncoder.xaml b/ObjetosSim/UserControls/ucGearEncoder.xaml new file mode 100644 index 0000000..7026982 --- /dev/null +++ b/ObjetosSim/UserControls/ucGearEncoder.xaml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + diff --git a/ObjetosSim/UserControls/ucGearEncoder.xaml.cs b/ObjetosSim/UserControls/ucGearEncoder.xaml.cs new file mode 100644 index 0000000..76f59e7 --- /dev/null +++ b/ObjetosSim/UserControls/ucGearEncoder.xaml.cs @@ -0,0 +1,154 @@ +using CtrEditor.Convertidores; +using CtrEditor.Siemens; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Media; +using Newtonsoft.Json; +using CommunityToolkit.Mvvm.ComponentModel; + +namespace CtrEditor.ObjetosSim.UserControls +{ + /// + /// Interaction logic for ucGearEncoder.xaml + /// + public partial class osGearEncoder : osBase, IosBase + { + private osBase _osMotor = null; + + // Otros datos y métodos relevantes para la simulación + + public static string NombreClase() + { + return "Ruota Fonica"; + } + private string nombre = NombreClase(); + public override string Nombre + { + get => nombre; + set => SetProperty(ref nombre, value); + } + + [ObservableProperty] + public string tag; + [ObservableProperty] + public bool pulso; + [ObservableProperty] + public float velocidadActual; + [ObservableProperty] + public float angulo; + [ObservableProperty] + public float dientes; + [ObservableProperty] + public float radio_Interno; + [ObservableProperty] + public float radio_Externo; + [ObservableProperty] + public float ancho_Dientes; + [ObservableProperty] + public float giros_segundo_a_50hz; + [ObservableProperty] + public string motor; + + partial void OnMotorChanged(string value) + { + _osMotor = ObtenerLink(Motor, typeof(osVMmotorSim)); + } + + + public osGearEncoder() + { + Ancho_Dientes = 0.5f; + Dientes = 10; + Radio_Interno = 0.5f; + Radio_Externo = 0.6f; + } + + public override void UpdateGeometryStart() + { + // Se llama antes de la simulacion + + } + public override void UpdatePLC(PLCModel plc, int elapsedMilliseconds) + { + if (_osMotor != null) + { + if (_osMotor is osVMmotorSim motor) + { + VelocidadActual = motor.Velocidad; + + // Calcular la cantidad de giros por segundo + double girosPorSegundo = (VelocidadActual / 50.0) * Giros_segundo_a_50hz; + + // Calcular la fracción del segundo que ha pasado + double segundosTranscurridos = elapsedMilliseconds / 1000.0; + + // Calcular el incremento de ángulo + double incrementoAngulo = (girosPorSegundo * 360.0) * segundosTranscurridos; + + // Actualizar el ángulo + Angulo = (float)(Angulo + incrementoAngulo) % 360; + + // Calcular la duración de un pulso + double duracionPulso = (360.0 / Dientes) / 2; + + // Generar pulsos cuadrados en función del ángulo + Pulso = ((Angulo % (360.0 / Dientes)) < duracionPulso) ? true : false; + + EscribirBitTag(Tag,Pulso); + } + } else if (Motor.Length>0) + _osMotor = ObtenerLink(Motor, typeof(osVMmotorSim)); + } + + + public override void UpdateControl(int elapsedMilliseconds) + { + // Calculamos la velocidad + + } + + public override void ucLoaded() + { + // El UserControl ya se ha cargado y podemos obtener las coordenadas para + // crear el objeto de simulacion + ActualizarLeftTop(); + + } + } + + public partial class ucGearEncoder : UserControl, IDataContainer + { + public osBase? Datos { get; set; } + + public ucGearEncoder() + { + InitializeComponent(); + this.Loaded += OnLoaded; + this.Unloaded += OnUnloaded; + } + private void OnLoaded(object sender, RoutedEventArgs e) + { + Datos?.ucLoaded(); + } + private void OnUnloaded(object sender, RoutedEventArgs e) + { + Datos?.ucUnLoaded(); + } + public void Resize(float width, float height) { } + public void Move(float LeftPixels, float TopPixels) + { + if (Datos != null) + { + Datos.Left = PixelToMeter.Instance.calc.PixelsToMeters(LeftPixels); + Datos.Top = PixelToMeter.Instance.calc.PixelsToMeters(TopPixels); + } + } + public void Rotate(float Angle) { } + public void Highlight(bool State) { } + public int ZIndex() + { + return 10; + } + } +} + diff --git a/ObjetosSim/UserControls/ucPhotocell.xaml.cs b/ObjetosSim/UserControls/ucPhotocell.xaml.cs index b7a4494..e6c53ed 100644 --- a/ObjetosSim/UserControls/ucPhotocell.xaml.cs +++ b/ObjetosSim/UserControls/ucPhotocell.xaml.cs @@ -38,6 +38,11 @@ namespace CtrEditor.ObjetosSim.UserControls Color = Brushes.Blue; else Color = Brushes.Green; + if (Tipo_NC) + EscribirBitTag(TagPhotocell_OUT, !LuzCortada); + else + EscribirBitTag(TagPhotocell_OUT, LuzCortada); + } [ObservableProperty] @@ -107,7 +112,6 @@ namespace CtrEditor.ObjetosSim.UserControls Simulation_Photocell.LuzCortada = false; } public override void UpdatePLC(PLCModel plc, int elapsedMilliseconds) { - EscribirBitTag(plc, TagPhotocell_OUT, LuzCortada); } public override void ucLoaded() { diff --git a/ObjetosSim/UserControls/ucSensTemperatura.xaml.cs b/ObjetosSim/UserControls/ucSensTemperatura.xaml.cs index 41f122c..b41c58f 100644 --- a/ObjetosSim/UserControls/ucSensTemperatura.xaml.cs +++ b/ObjetosSim/UserControls/ucSensTemperatura.xaml.cs @@ -32,6 +32,12 @@ namespace CtrEditor.ObjetosSim public float max_OUT_Scaled; [ObservableProperty] public float value; + + partial void OnValueChanged(float value) + { + EscribirWordTagScaled(Tag, value, 0, 100, Min_OUT_Scaled, Max_OUT_Scaled); + } + [ObservableProperty] public float ancho; [ObservableProperty] @@ -49,7 +55,7 @@ namespace CtrEditor.ObjetosSim public override void UpdatePLC(PLCModel plc, int elapsedMilliseconds) { - EscribirWordTagScaled(plc, Tag, Value, 0, 100, Min_OUT_Scaled, Max_OUT_Scaled); + } public override void ucLoaded() diff --git a/ObjetosSim/UserControls/ucTanque.xaml.cs b/ObjetosSim/UserControls/ucTanque.xaml.cs index fc90fc8..4b9dce8 100644 --- a/ObjetosSim/UserControls/ucTanque.xaml.cs +++ b/ObjetosSim/UserControls/ucTanque.xaml.cs @@ -63,9 +63,9 @@ namespace CtrEditor.ObjetosSim public override void UpdatePLC(PLCModel plc, int elapsedMilliseconds) { - EscribirWordTagScaled(plc, TagNivel_Word, Level, 0, 100, Min_OUT_Scaled, Max_OUT_Scaled); - Ingreso_Abierto = LeerBitTag(plc, TagIngresoAbierto_Bool); - Salida_Abierta = LeerBitTag(plc, TagSalidaAbierta_Bool); + EscribirWordTagScaled(TagNivel_Word, Level, 0, 100, Min_OUT_Scaled, Max_OUT_Scaled); + Ingreso_Abierto = LeerBitTag(TagIngresoAbierto_Bool); + Salida_Abierta = LeerBitTag(TagSalidaAbierta_Bool); } public override void UpdateControl(int elapsedMilliseconds) diff --git a/ObjetosSim/UserControls/ucTransporteGuias.xaml b/ObjetosSim/UserControls/ucTransporteGuias.xaml index 68a0486..f321731 100644 --- a/ObjetosSim/UserControls/ucTransporteGuias.xaml +++ b/ObjetosSim/UserControls/ucTransporteGuias.xaml @@ -20,8 +20,8 @@ - - + + diff --git a/ObjetosSim/UserControls/ucTransporteGuias.xaml.cs b/ObjetosSim/UserControls/ucTransporteGuias.xaml.cs index 27df54b..63a0179 100644 --- a/ObjetosSim/UserControls/ucTransporteGuias.xaml.cs +++ b/ObjetosSim/UserControls/ucTransporteGuias.xaml.cs @@ -48,6 +48,12 @@ namespace CtrEditor.ObjetosSim [ObservableProperty] public string motor; + + partial void OnMotorChanged(string value) + { + _osMotor = ObtenerLink(Motor, typeof(osVMmotorSim)); + } + [ObservableProperty] public float ancho; [ObservableProperty] @@ -105,8 +111,7 @@ namespace CtrEditor.ObjetosSim { if (_osMotor is osVMmotorSim motor) VelocidadActual = motor.Velocidad; - } - else + } else if (Motor.Length > 0) _osMotor = ObtenerLink(Motor, typeof(osVMmotorSim)); } diff --git a/ObjetosSim/UserControls/ucTransporteTTop.xaml.cs b/ObjetosSim/UserControls/ucTransporteTTop.xaml.cs index b9677d2..6cf177b 100644 --- a/ObjetosSim/UserControls/ucTransporteTTop.xaml.cs +++ b/ObjetosSim/UserControls/ucTransporteTTop.xaml.cs @@ -51,6 +51,12 @@ namespace CtrEditor.ObjetosSim [ObservableProperty] public string motor; + + partial void OnMotorChanged(string value) + { + _osMotor = ObtenerLink(Motor, typeof(osVMmotorSim)); + } + [ObservableProperty] public float ancho; [ObservableProperty] @@ -101,7 +107,7 @@ namespace CtrEditor.ObjetosSim if (_osMotor is osVMmotorSim motor) VelocidadActual = motor.Velocidad; } - else + else if (Motor.Length > 0) _osMotor = ObtenerLink(Motor, typeof(osVMmotorSim)); } diff --git a/ObjetosSim/osBase.cs b/ObjetosSim/osBase.cs index 254ef1a..028230e 100644 --- a/ObjetosSim/osBase.cs +++ b/ObjetosSim/osBase.cs @@ -104,6 +104,9 @@ namespace CtrEditor.ObjetosSim [JsonIgnore] protected UserControl? _visualRepresentation = null; + [JsonIgnore] + protected PLCModel? _plc = null; + public virtual void UpdateControl(int elapsedMilliseconds) { } public virtual void UpdateGeometryStart() { @@ -149,6 +152,11 @@ namespace CtrEditor.ObjetosSim DataSave.DataRestoreAfterSerialize(out _mainViewModel,out _visualRepresentation,out simulationManager); } + public void SetPLC(PLCModel plc) + { + _plc = plc; + } + protected osBase ObtenerLink(string NameLink, Type tipoOsBase) { if (!string.IsNullOrEmpty(NameLink) && _mainViewModel != null) @@ -201,45 +209,48 @@ namespace CtrEditor.ObjetosSim CanvasSetTopinMeter(Top); } - public bool LeerBitTag(PLCModel plc, string Tag) + public bool LeerBitTag(string Tag) { + if (this._plc == null) return false; if (!string.IsNullOrEmpty(Tag)) { if (Tag == "1") return true; else if (Tag == "0") return false; - if (plc != null) - return plc.LeerTagBool(Tag); + if (_plc != null) + return _plc.LeerTagBool(Tag); } return false; } - public void EscribirBitTag(PLCModel plc, string Tag, bool Value) + public void EscribirBitTag(string Tag, bool Value) { + if (_plc == null) return; if (!string.IsNullOrEmpty(Tag)) - if (plc != null) - plc.EscribirTagBool(Tag, Value); + if (_plc != null) + _plc.EscribirTagBool(Tag, Value); } - public void EscribirWordTagScaled(PLCModel plc, string Tag, float Value, float IN_scale_Min, float IN_scale_Max, float OUT_scale_Min, float OUT_scale_Max) + public void EscribirWordTagScaled(string Tag, float Value, float IN_scale_Min, float IN_scale_Max, float OUT_scale_Min, float OUT_scale_Max) { - if (plc != null) - if (!string.IsNullOrEmpty(Tag)) - { - SDataValue plcData = new SDataValue(); - plcData.UInt16 = (ushort)((Value - IN_scale_Min) / (IN_scale_Max - IN_scale_Min) * (OUT_scale_Max - OUT_scale_Min) + OUT_scale_Min); - plc.EscribirTag(Tag, plcData); - } + if (_plc == null) return; + if (!string.IsNullOrEmpty(Tag)) + { + SDataValue plcData = new SDataValue(); + plcData.UInt16 = (ushort)((Value - IN_scale_Min) / (IN_scale_Max - IN_scale_Min) * (OUT_scale_Max - OUT_scale_Min) + OUT_scale_Min); + _plc.EscribirTag(Tag, plcData); + } } - public float LeerWordTagScaled(PLCModel plc, string Tag, float IN_scale_Min, float IN_scale_Max, float OUT_scale_Min, float OUT_scale_Max) + public float LeerWordTagScaled(PLCModel _plc, string Tag, float IN_scale_Min, float IN_scale_Max, float OUT_scale_Min, float OUT_scale_Max) { + if (_plc == null) return 0; if (!string.IsNullOrEmpty(Tag)) { if (float.TryParse(Tag, out float v)) return v; - if (plc != null) + if (_plc != null) { - SDataValue plcData = plc.LeerTag(Tag); + SDataValue plcData = _plc.LeerTag(Tag); float Value = plcData.UInt16; // WORD return (Value - OUT_scale_Min) / (OUT_scale_Max - OUT_scale_Min) * (IN_scale_Max - IN_scale_Min) + IN_scale_Min; } diff --git a/Siemens/PLCControl.xaml.cs b/Siemens/PLCControl.xaml.cs index 4f46644..1ad8fd7 100644 --- a/Siemens/PLCControl.xaml.cs +++ b/Siemens/PLCControl.xaml.cs @@ -167,7 +167,7 @@ namespace CtrEditor.Siemens IsConfigured = false; try { - Instance?.UpdateTagList( ETagListDetails.IO | ETagListDetails.DB); + Instance?.UpdateTagList(ETagListDetails.IO | ETagListDetails.DB, true); // ETagListDetails.IO | ETagListDetails.DB IsConfigured = true; } catch (Exception ex) diff --git a/Simulacion/FPhysics.cs b/Simulacion/FPhysics.cs index ef55062..4a8d902 100644 --- a/Simulacion/FPhysics.cs +++ b/Simulacion/FPhysics.cs @@ -334,7 +334,7 @@ namespace CtrEditor.Simulacion Body.LinearDamping = 0f; // Ajustar para controlar la reducción de la velocidad lineal Body.AngularDamping = 0f; // Ajustar para controlar la reducción de la velocidad angular Body.Restitution = 0.2f; // Baja restitución para menos rebote - // Body.IsBullet = true; + Body.IsBullet = true; } public void SetDiameter(float diameter)