diff --git a/CtrEditor.csproj b/CtrEditor.csproj index 9a88f2c..9b3f0af 100644 --- a/CtrEditor.csproj +++ b/CtrEditor.csproj @@ -20,6 +20,9 @@ + + + @@ -42,7 +45,6 @@ - @@ -58,7 +60,9 @@ - + + + diff --git a/MainViewModel.cs b/MainViewModel.cs index 61d074b..7ad26c2 100644 --- a/MainViewModel.cs +++ b/MainViewModel.cs @@ -37,14 +37,9 @@ namespace CtrEditor public DatosDeTrabajo datosDeTrabajo { get; } public ObservableCollection listaImagenes { get; private set; } // Publicación de las claves del diccionario public ObservableCollection ListaOsBase { get; } = new ObservableCollection(); - private ObservableCollection _objetosSimulables = new ObservableCollection(); - public PLCViewModel plcViewModelData; public Stopwatch stopwatch_PLCRefresh; public Stopwatch stopwatch_SimRefresh; - private bool isSimulationRunning; - private bool isConnected; - public SimulationManagerFP simulationManager = new SimulationManagerFP(); private readonly DispatcherTimer _timerSimulacion; @@ -59,11 +54,153 @@ namespace CtrEditor public ICommand TBConnectPLCCommand { get; } public ICommand TBDisconnectPLCCommand { get; } + public ICommand OpenWorkDirectoryCommand { get; } + // Evento que se dispara cuando se selecciona una nueva imagen public event EventHandler ImageSelected; public event EventHandler TickSimulacion; public event Action OnUserControlSelected; + + private bool isSimulationRunning; + private bool isConnected; + public PLCViewModel plcViewModelData; + private osBase _selectedItemOsList; + private string _selectedImage = null; + private ObservableCollection _objetosSimulables = new ObservableCollection(); + private float _left; + private float _top; + + public float CanvasLeft + { + get => _left; + set + { + _left = value; + OnPropertyChanged(nameof(CanvasLeft)); + } + } + public float CanvasTop + { + get => _top; + set + { + _top = value; + OnPropertyChanged(nameof(CanvasTop)); + } + } + + public bool IsSimulationRunning + { + get => isSimulationRunning; + set + { + isSimulationRunning = value; + OnPropertyChanged(nameof(IsSimulationRunning)); + CommandManager.InvalidateRequerySuggested(); // Notificar que el estado de los comandos ha cambiado + } + } + + public bool IsConnected + { + get => isConnected; + set + { + isConnected = value; + OnPropertyChanged(nameof(IsConnected)); + CommandManager.InvalidateRequerySuggested(); + } + } + + public string directorioTrabajo + { + get => EstadoPersistente.Instance.directorio; + set + { + if (value != null) + { + EstadoPersistente.Instance.directorio = value; // Actualizar el estado persistente + EstadoPersistente.Instance.GuardarEstado(); // Guardar el estado actualizado + datosDeTrabajo.CargarImagenes(); + listaImagenes = new ObservableCollection(datosDeTrabajo.Imagenes.Keys); // Actualizar claves + SelectedImage = null; + 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 + } + } + } + + public PLCViewModel PLCViewModel + { + get { return plcViewModelData; } + set + { + plcViewModelData = value; + OnPropertyChanged(nameof(PLCViewModel)); + } + } + + public string SelectedImage + { + get => _selectedImage; + set + { + if (_selectedImage != value && value != null) + { + StopSimulation(); + SaveStateObjetosSimulables(); // Guarda el estado antes de cambiar la imagen + _selectedImage = value; + ImageSelected?.Invoke(this, datosDeTrabajo.Imagenes[value]); // Dispara el evento con la nueva ruta de imagen + LoadStateObjetosSimulables(); + } + _selectedImage = value; + OnPropertyChanged(nameof(SelectedImage)); + } + } + + public osBase SelectedItemOsList + { + get => _selectedItemOsList; + set + { + if (_selectedItemOsList != value) + { + _selectedItemOsList = value; + OnPropertyChanged(nameof(SelectedItemOsList)); + } + } + } + + private TipoSimulable _selectedItem = null; + public TipoSimulable SelectedItem + { + get => _selectedItem; + set + { + if (_selectedItem != value) + { + _selectedItem = value; + OnPropertyChanged(nameof(SelectedItem)); // Notificar que la propiedad ha cambiado + } + } + } + + public ObservableCollection ObjetosSimulables + { + get => _objetosSimulables; + set + { + if (_objetosSimulables != value) + { + _objetosSimulables = value; + OnPropertyChanged(nameof(ObjetosSimulables)); + } + } + } + + public MainViewModel() { OpenWorkDirectoryCommand = new RelayCommand(OpenWorkDirectory); @@ -101,33 +238,44 @@ namespace CtrEditor } - private TipoSimulable _selectedItem = null; - public TipoSimulable SelectedItem + + public void CrearUserControl(Type tipoSimulable) { - get => _selectedItem; - set + // Crear una nueva instancia del osBase correspondiente + osBase? newosBase = UserControlFactory.GetInstanceForType(tipoSimulable); + if (newosBase != null) { - if (_selectedItem != value) - { - _selectedItem = value; - OnPropertyChanged(nameof(SelectedItem)); // Notificar que la propiedad ha cambiado - } + if (CrearUsercontrol(newosBase)) + // Añadir el nuevo osBase a la colección de objetos simulables + ObjetosSimulables.Add(newosBase); } } + private bool CrearUsercontrol(osBase osObjeto) + { + Type tipoObjeto = osObjeto.GetType(); + + // Obtén el UserControl correspondiente para el tipo de objeto + UserControl? userControl = UserControlFactory.GetControlForType(tipoObjeto); + + if (userControl != null) + { + // Asignar los datos al UserControl + UserControlFactory.AssignDatos(userControl, osObjeto, simulationManager); + osObjeto._mainViewModel = this; + + OnUserControlSelected?.Invoke(userControl); + + return true; + } + return false; + } private void ExecuteDoubleClick(object parameter) { if (parameter is TipoSimulable tipoSimulable) { - // Crear una nueva instancia del osBase correspondiente - osBase? newosBase = UserControlFactory.GetInstanceForType(tipoSimulable.Tipo); - if (newosBase != null) - { - if (CrearUsercontrol(newosBase)) - // Añadir el nuevo osBase a la colección de objetos simulables - ObjetosSimulables.Add(newosBase); - } + CrearUserControl(tipoSimulable.Tipo); } } @@ -144,28 +292,6 @@ namespace CtrEditor } } - public bool IsSimulationRunning - { - get => isSimulationRunning; - set - { - isSimulationRunning = value; - OnPropertyChanged(nameof(IsSimulationRunning)); - CommandManager.InvalidateRequerySuggested(); // Notificar que el estado de los comandos ha cambiado - } - } - - public bool IsConnected - { - get => isConnected; - set - { - isConnected = value; - OnPropertyChanged(nameof(IsConnected)); - CommandManager.InvalidateRequerySuggested(); - } - } - private void StartSimulation() { foreach (var objetoSimulable in ObjetosSimulables) @@ -238,77 +364,6 @@ namespace CtrEditor } - //protected virtual void OnTickSimulacion(TickSimulacionEventArgs e) - //{ - // TickSimulacion?.Invoke(this, e); - //} - - public string directorioTrabajo - { - get => EstadoPersistente.Instance.directorio; - set - { - if (value != null) - { - EstadoPersistente.Instance.directorio = value; // Actualizar el estado persistente - EstadoPersistente.Instance.GuardarEstado(); // Guardar el estado actualizado - datosDeTrabajo.CargarImagenes(); - listaImagenes = new ObservableCollection(datosDeTrabajo.Imagenes.Keys); // Actualizar claves - SelectedImage = null; - 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 - } - } - } - - - public PLCViewModel PLCViewModel - { - get { return plcViewModelData; } - set - { - plcViewModelData = value; - OnPropertyChanged(nameof(PLCViewModel)); - } - } - - private string _selectedImage = null; - public string SelectedImage - { - get => _selectedImage; - set - { - if (_selectedImage != value && value != null) - { - StopSimulation(); - SaveStateObjetosSimulables(); // Guarda el estado antes de cambiar la imagen - _selectedImage = value; - ImageSelected?.Invoke(this, datosDeTrabajo.Imagenes[value]); // Dispara el evento con la nueva ruta de imagen - LoadStateObjetosSimulables(); - } - _selectedImage = value; - OnPropertyChanged(nameof(SelectedImage)); - } - } - - private osBase _selectedItemOsList; - public osBase SelectedItemOsList - { - get => _selectedItemOsList; - set - { - if (_selectedItemOsList != value) - { - _selectedItemOsList = value; - OnPropertyChanged(nameof(SelectedItemOsList)); - } - } - } - - public ICommand OpenWorkDirectoryCommand { get; } - private void OpenWorkDirectory() { var dialog = new VistaFolderBrowserDialog(); @@ -322,20 +377,6 @@ namespace CtrEditor // Lista de osBase // - - public ObservableCollection ObjetosSimulables - { - get => _objetosSimulables; - set - { - if (_objetosSimulables != value) - { - _objetosSimulables = value; - OnPropertyChanged(nameof(ObjetosSimulables)); - } - } - } - public void Save() { SaveStateObjetosSimulables(); @@ -423,28 +464,6 @@ namespace CtrEditor } - private bool CrearUsercontrol(osBase osObjeto) - { - Type tipoObjeto = osObjeto.GetType(); - - // Obtén el UserControl correspondiente para el tipo de objeto - UserControl? userControl = UserControlFactory.GetControlForType(tipoObjeto); - - if (userControl != null) - { - // Asignar los datos al UserControl - UserControlFactory.AssignDatos(userControl, osObjeto, simulationManager); - osObjeto._mainViewModel = this; - - OnUserControlSelected?.Invoke(userControl); - - return true; - } - return false; - } - - - // Implementación de INotifyPropertyChanged... public event PropertyChangedEventHandler PropertyChanged; diff --git a/MainWindow.xaml.cs b/MainWindow.xaml.cs index bcd5029..2709948 100644 --- a/MainWindow.xaml.cs +++ b/MainWindow.xaml.cs @@ -22,7 +22,6 @@ using UserControl = System.Windows.Controls.UserControl; using CheckBox = System.Windows.Controls.CheckBox; using Orientation = System.Windows.Controls.Orientation; using ListBox = System.Windows.Controls.ListBox; -//using OpenCvSharp; namespace CtrEditor @@ -70,6 +69,33 @@ namespace CtrEditor } } + private (float X, float Y) ObtenerCentroCanvasPixels() + { + var scaleTransform = ImagenEnTrabajoCanvas.LayoutTransform as ScaleTransform; + float scaleX = (float)(scaleTransform?.ScaleX ?? 1.0); + float scaleY = (float)(scaleTransform?.ScaleY ?? 1.0); + + // Obtiene el área visible del ScrollViewer + float visibleWidth = (float)ImagenEnTrabajoScrollViewer.ViewportWidth; + float visibleHeight = (float)ImagenEnTrabajoScrollViewer.ViewportHeight; + + // Obtiene la posición actual del desplazamiento ajustada por el zoom + float offsetX = (float)ImagenEnTrabajoScrollViewer.HorizontalOffset / scaleX; + float offsetY = (float)ImagenEnTrabajoScrollViewer.VerticalOffset / scaleY; + + // Calcula el centro visible ajustado + float centerX = offsetX + (visibleWidth / scaleX) / 2; + float centerY = offsetY + (visibleHeight / scaleY) / 2; + + return (centerX, centerY); + } + + private (float X, float Y) ObtenerCentroCanvasMeters() + { + var c = ObtenerCentroCanvasPixels(); + return (PixelToMeter.Instance.calc.PixelsToMeters(c.X), PixelToMeter.Instance.calc.PixelsToMeters(c.Y)); + } + private void AgregarUserControl(UserControl userControl) { if (userControl is IDataContainer dataContainer) @@ -78,26 +104,12 @@ namespace CtrEditor if (!NuevoOS.Inicializado) // Aun no fue inicializado { Random rnd = new Random(); - // Obtiene el factor de escala - var scaleTransform = ImagenEnTrabajoCanvas.LayoutTransform as ScaleTransform; - double scaleX = scaleTransform?.ScaleX ?? 1.0; - double scaleY = scaleTransform?.ScaleY ?? 1.0; - // Obtiene el área visible del ScrollViewer - double visibleWidth = ImagenEnTrabajoScrollViewer.ViewportWidth; - double visibleHeight = ImagenEnTrabajoScrollViewer.ViewportHeight; - - // Obtiene la posición actual del desplazamiento ajustada por el zoom - double offsetX = ImagenEnTrabajoScrollViewer.HorizontalOffset / scaleX; - double offsetY = ImagenEnTrabajoScrollViewer.VerticalOffset / scaleY; - - // Calcula el centro visible ajustado - double centerX = offsetX + (visibleWidth / scaleX) / 2; - double centerY = offsetY + (visibleHeight / scaleY) / 2; + var centro = ObtenerCentroCanvasPixels(); // Ajusta la posición del UserControl para que esté centrado en el área visible - double leftPixels = centerX - (userControl.ActualWidth / 2); - double topPixels = centerY - (userControl.ActualHeight / 2); + double leftPixels = centro.X - (userControl.ActualWidth / 2); + double topPixels = centro.Y - (userControl.ActualHeight / 2); // Establece la posición del UserControl NuevoOS.Left = PixelToMeter.Instance.calc.PixelsToMeters((float)leftPixels + (float)(rnd.NextDouble() - 0.5) ); diff --git a/ObjetosSim/UserControlFactory.cs b/ObjetosSim/UserControlFactory.cs index e281b25..f792f63 100644 --- a/ObjetosSim/UserControlFactory.cs +++ b/ObjetosSim/UserControlFactory.cs @@ -31,6 +31,8 @@ namespace CtrEditor.ObjetosSim return new ucTanque(); if (tipoObjeto == typeof(osSensTemperatura)) return new ucSensTemperatura(); + if (tipoObjeto == typeof(osFiller)) + return new ucFiller(); // Puedes añadir más condiciones para otros tipos @@ -58,6 +60,8 @@ namespace CtrEditor.ObjetosSim return new osTanque(); if (tipoObjeto == typeof(osSensTemperatura)) return new osSensTemperatura(); + if (tipoObjeto == typeof(osFiller)) + return new osFiller(); // Puedes añadir más condiciones para otros tipos diff --git a/ObjetosSim/osBase.cs b/ObjetosSim/osBase.cs index 624d1da..607e349 100644 --- a/ObjetosSim/osBase.cs +++ b/ObjetosSim/osBase.cs @@ -18,6 +18,7 @@ using System.Windows.Media; using Microsoft.Xna.Framework; using FarseerPhysics.Dynamics; using Siemens.Simatic.Simulation.Runtime; +using System.Windows.Media.Imaging; namespace CtrEditor.ObjetosSim { @@ -33,6 +34,7 @@ namespace CtrEditor.ObjetosSim public interface IDataContainer { + [JsonIgnore] osBase? Datos { get; set; } void Resize(float width, float height); void Move(float Left, float Top); @@ -47,7 +49,8 @@ namespace CtrEditor.ObjetosSim public abstract float Top { get; set; } public bool Inicializado = false; - + + [JsonIgnore] protected UserControl? _visualRepresentation = null; public abstract string Nombre { get; set; } @@ -241,6 +244,28 @@ namespace CtrEditor.ObjetosSim return simulationManager.AddLine(coords.Start, coords.End); } + public ImageSource ImageFromPath(string value) + { + if (value is string stringValue) + { + return new BitmapImage(new Uri(stringValue, UriKind.RelativeOrAbsolute)); + } + return null; + } + + static protected T GetLastElement(List list) where T : class + { + if (list.Count > 0) + { + return list[list.Count - 1]; + } + else + { + return null; + } + } + + public event PropertyChangedEventHandler PropertyChanged; diff --git a/ObjetosSim/ucBasicExample.xaml b/ObjetosSim/ucBasicExample.xaml index 4da1c1f..4da0235 100644 --- a/ObjetosSim/ucBasicExample.xaml +++ b/ObjetosSim/ucBasicExample.xaml @@ -13,8 +13,12 @@ + Width="{Binding Ancho, Converter={StaticResource MeterToPixelConverter}}" + Height="{Binding Alto, Converter={StaticResource MeterToPixelConverter}}" + Stretch="Uniform"> + + + + diff --git a/ObjetosSim/ucBasicExample.xaml.cs b/ObjetosSim/ucBasicExample.xaml.cs index ff5445e..7448c26 100644 --- a/ObjetosSim/ucBasicExample.xaml.cs +++ b/ObjetosSim/ucBasicExample.xaml.cs @@ -27,9 +27,9 @@ namespace CtrEditor.ObjetosSim private string _nombre = "Ejemplo"; private float _ancho; private float _alto; + private float _angulo; private float _left; private float _top; - private float _angulo; public override float Left { @@ -112,7 +112,7 @@ namespace CtrEditor.ObjetosSim { } - public override void UpdateControl() + public override void UpdateControl(int elapsedMilliseconds) { } diff --git a/ObjetosSim/ucFiller.xaml b/ObjetosSim/ucFiller.xaml new file mode 100644 index 0000000..f39e039 --- /dev/null +++ b/ObjetosSim/ucFiller.xaml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + diff --git a/ObjetosSim/ucFiller.xaml.cs b/ObjetosSim/ucFiller.xaml.cs new file mode 100644 index 0000000..8c0ceb9 --- /dev/null +++ b/ObjetosSim/ucFiller.xaml.cs @@ -0,0 +1,242 @@ +using CtrEditor.Convertidores; +using CtrEditor.Siemens; +using CtrEditor.Simulacion; +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; +using Microsoft.Xna.Framework; + +namespace CtrEditor.ObjetosSim +{ + /// + /// Interaction logic for ucFiller.xaml + /// + public class osFiller : osBase + { + // Otros datos y métodos relevantes para la simulación + + private string _nombre = "Filler"; + private float _ancho; + private float _alto; + private float _left; + private float _top; + private float _angulo; + private float _botellas_hora; + private float _velocidad_actual; + private float _diametro_botella; + private string _tag_consenso; + private bool _consenso; + private float TiempoRestante; + private List Botellas = new List(); + + public bool Consenso + { + get => _consenso; + set + { + _consenso = value; + OnPropertyChanged(nameof(Consenso)); + } + } + + public float Botellas_hora + { + get => _botellas_hora; + set + { + _botellas_hora = value; + OnPropertyChanged(nameof(Botellas_hora)); + } + } + public float Velocidad_actual_percentual + { + get => _velocidad_actual; + set + { + _velocidad_actual = value; + OnPropertyChanged(nameof(Velocidad_actual_percentual)); + } + } + public float Diametro_botella + { + get => _diametro_botella; + set + { + _diametro_botella = value; + OnPropertyChanged(nameof(Diametro_botella)); + } + } + public string Tag_consenso + { + get => _tag_consenso; + set + { + _tag_consenso = value; + OnPropertyChanged(nameof(Tag_consenso)); + } + } + + public override float Left + { + get => _left; + set + { + _left = value; + CanvasSetLeftinMeter(value); + OnPropertyChanged(nameof(Left)); + } + } + public override float Top + { + get => _top; + set + { + _top = value; + CanvasSetTopinMeter(value); + OnPropertyChanged(nameof(Top)); + } + } + + public float Ancho + { + get => _ancho; + set + { + _ancho = value; + OnPropertyChanged(nameof(Ancho)); + } + } + public float Alto + { + get => _alto; + set + { + _alto = value; + OnPropertyChanged(nameof(Alto)); + } + } + + public float Angulo + { + get => _angulo; + set + { + _angulo = value; + OnPropertyChanged(nameof(Angulo)); + } + } + + public override string Nombre + { + get => _nombre; + set + { + if (_nombre != value) + { + _nombre = value; + OnPropertyChanged(nameof(Nombre)); + } + } + } + + public osFiller() + { + Ancho = 0.30f; + Alto = 0.30f; + Angulo = 0; + Velocidad_actual_percentual = 0; + Diametro_botella = 0.1f; + Botellas_hora = 10000; + } + + public override void UpdateGeometryStart() + { + // Se llama antes de la simulacion + + } + public override void UpdateGeometryStep() + { + } + public override void UpdatePLC(PLCModel plc, int elapsedMilliseconds) + { + Consenso = LeerBitTag(plc, Tag_consenso); + } + + public override void UpdateControl(int elapsedMilliseconds) + { + if (Consenso && Velocidad_actual_percentual>0) + { + TiempoRestante -= elapsedMilliseconds / 1000.0f; + if (TiempoRestante <= 0) + { + TiempoRestante = Botellas_hora * (Velocidad_actual_percentual / 100.0f) / 3600.0f; + var PosSalida = new Vector2(Left, Top); + + var UltimaBotellla = GetLastElement(Botellas); + if (UltimaBotellla != null && UltimaBotellla.Center != PosSalida) + Botellas.Add(simulationManager.AddCircle(Diametro_botella, PosSalida, 1)); + } + } + } + public override void ucLoaded() + { + // El UserControl ya se ha cargado y podemos obtener las coordenadas para + // crear el objeto de simulacion + } + + } + + public partial class ucFiller : UserControl, IDataContainer + { + public osBase? Datos { get; set; } + + public ucFiller() + { + InitializeComponent(); + this.Loaded += OnLoaded; + } + private void OnLoaded(object sender, RoutedEventArgs e) + { + Datos?.ucLoaded(); + } + public void Resize(float width, float height) + { + if (Datos is osFiller datos) + { + datos.Ancho = PixelToMeter.Instance.calc.PixelsToMeters(width); + datos.Alto = PixelToMeter.Instance.calc.PixelsToMeters(width); + } + } + 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) + { + if (Datos != null) + if (Datos is osFiller datos) + datos.Angulo = Angle; + } + public void Highlight(bool State) { } + public int ZIndex() + { + return 10; + } + } + +} diff --git a/ObjetosSim/ucTanque.xaml.cs b/ObjetosSim/ucTanque.xaml.cs index 0bb4d24..1b431fc 100644 --- a/ObjetosSim/ucTanque.xaml.cs +++ b/ObjetosSim/ucTanque.xaml.cs @@ -1,7 +1,6 @@ using CtrEditor.Convertidores; using CtrEditor.Siemens; using Newtonsoft.Json.Linq; -using OpenCvSharp.Flann; using Siemens.Simatic.Simulation.Runtime; using System; using System.Collections.Generic; @@ -46,7 +45,6 @@ namespace CtrEditor.ObjetosSim private bool _SalidaAbierta_Bool; private float _capacidadLitros; - public float Capacidad_Litros { get => _capacidadLitros; diff --git a/ObjetosSim/ucVMmotorSim.xaml b/ObjetosSim/ucVMmotorSim.xaml index 0379f7e..6297680 100644 --- a/ObjetosSim/ucVMmotorSim.xaml +++ b/ObjetosSim/ucVMmotorSim.xaml @@ -12,7 +12,7 @@ - diff --git a/ObjetosSim/ucVMmotorSim.xaml.cs b/ObjetosSim/ucVMmotorSim.xaml.cs index edad0f9..438a43d 100644 --- a/ObjetosSim/ucVMmotorSim.xaml.cs +++ b/ObjetosSim/ucVMmotorSim.xaml.cs @@ -15,6 +15,7 @@ using System.Windows.Media.Imaging; using System.Windows.Navigation; using System.Windows.Shapes; using CtrEditor.Simulacion; +using Newtonsoft.Json; namespace CtrEditor.ObjetosSim { @@ -22,25 +23,10 @@ namespace CtrEditor.ObjetosSim /// Interaction logic for ucVMmotorSim.xaml /// /// - public class VMSimMotor - { - public bool _STATUS_VFD_Ready; - public float STATUS_VFD_ACT_Speed_Hz; - public bool Motor_Running; - public bool STATUS_VFD_Trip; - public bool STATUS_VFD_Warning; - public bool STATUS_VFD_Coasting; - public bool OUT_Run; - public bool OUT_Stop; - public bool OUT_Reversal; - public float OUT_OUT_VFD_REQ_Speed_Hz; - } - public class osVMmotorSim : osBase { - // Otros datos y métodos relevantes para la simulación private string _nombre = "VetroMeccanica Motor"; @@ -53,9 +39,21 @@ namespace CtrEditor.ObjetosSim private bool _encendido; private float _rampaSegundos; private float _maxHz; + private ImageSource _imageSource; + + private VMSimMotor motState = new VMSimMotor(); - public VMSimMotor motState = new VMSimMotor(); - + [Hidden] + [JsonIgnore] + public ImageSource ImageSource + { + get { return _imageSource; } + set + { + _imageSource = value; + OnPropertyChanged(nameof(ImageSource)); + } + } public float Tamano { @@ -89,13 +87,12 @@ namespace CtrEditor.ObjetosSim } } - public bool Encendido { get => _encendido; set { - _encendido = value; + _encendido = value; OnPropertyChanged(nameof(Encendido)); } } @@ -156,7 +153,12 @@ namespace CtrEditor.ObjetosSim public float Velocidad { get => _velocidad; set { - _velocidad = value; + _velocidad = value; + if (value > 0) + ImageSource = ImageFromPath("/imagenes/motorVerde.png"); + else + ImageSource = ImageFromPath("/imagenes/motorNegro.png"); + OnPropertyChanged(nameof(Velocidad)); } } @@ -167,7 +169,8 @@ namespace CtrEditor.ObjetosSim PLC_NumeroMotor = 31; MaxRatedHz = 100; TiempoRampa = 3; - } + ImageSource = ImageFromPath("/imagenes/motor2.png"); + } public override void UpdateGeometryStart() { @@ -178,68 +181,19 @@ namespace CtrEditor.ObjetosSim { } public override void UpdatePLC(PLCModel plc, int elapsedMilliseconds) { - var index = 0; - switch (PLC_NumeroMotor) - { - case < 100: - index = (int)PLC_NumeroMotor-30+300; - break; - } - motState.OUT_Run = plc.LeerTagBool($"\"DB MotorSimulate\".Motors[{index}].OUT.Run"); - motState.OUT_Reversal = plc.LeerTagBool($"\"DB MotorSimulate\".Motors[{index}].OUT.\"Reversal Direction\""); - motState.OUT_OUT_VFD_REQ_Speed_Hz = (float)plc.LeerTagInt16($"\"DB MotorSimulate\".Motors[{index}].OUT.OUT_VFD_REQ_Speed_Hz"); + motState.UpdatePLC(plc,PLC_NumeroMotor,Encendido, elapsedMilliseconds); + Velocidad = motState.STATUS_VFD_ACT_Speed_Hz / 10; - - - if (Encendido) - { - motState._STATUS_VFD_Ready = true; - motState.Motor_Running = true; - motState.STATUS_VFD_Trip = false; - motState.STATUS_VFD_Warning = false; - motState.STATUS_VFD_Coasting = false; - } - else - { - motState._STATUS_VFD_Ready = false; - motState.Motor_Running = false; - motState.STATUS_VFD_Trip = true; - motState.STATUS_VFD_Warning = false; - motState.STATUS_VFD_Coasting = false; - } - - // Calculamos la velocidad - motState.STATUS_VFD_ACT_Speed_Hz += CalcSpeedRamp(motState.STATUS_VFD_ACT_Speed_Hz, motState.OUT_OUT_VFD_REQ_Speed_Hz, elapsedMilliseconds); - - plc.EscribirTagBool($"\"DB MotorSimulate\".Motors[{index}].STATUS_VFD_Ready", motState._STATUS_VFD_Ready); - plc.EscribirTagBool($"\"DB MotorSimulate\".Motors[{index}].Motor_Running", motState.Motor_Running); - plc.EscribirTagBool($"\"DB MotorSimulate\".Motors[{index}].STATUS_VFD_Trip", motState.STATUS_VFD_Trip); - plc.EscribirTagBool($"\"DB MotorSimulate\".Motors[{index}].STATUS_VFD_Warning", motState.STATUS_VFD_Warning); - plc.EscribirTagBool($"\"DB MotorSimulate\".Motors[{index}].STATUS_VFD_Coasting", motState.STATUS_VFD_Coasting); - - plc.EscribirTagInt16($"\"DB MotorSimulate\".Motors[{index}].STATUS_VFD_ACT_Speed_Hz",(int)motState.STATUS_VFD_ACT_Speed_Hz); - - Velocidad = motState.STATUS_VFD_ACT_Speed_Hz/10; - } - - private float CalcSpeedRamp(float actual, float expected, int elapsedMilliseconds) - { - float hzIncrementsRamp = (MaxRatedHz * 10) / (TiempoRampa * (1000.0f / elapsedMilliseconds)); - float delta = expected - actual; - // Conrtolar si la diferencia no es mayor de lo que falta - if (Math.Abs(hzIncrementsRamp)>Math.Abs(delta)) - hzIncrementsRamp = Math.Abs(delta); - if (delta < 0) - return -hzIncrementsRamp; - else - return hzIncrementsRamp; } public override void UpdateControl(int elapsedMilliseconds) { + // Calculamos la velocidad + motState.UpdateSpeed(MaxRatedHz,TiempoRampa, elapsedMilliseconds); } + public override void ucLoaded() { // El UserControl ya se ha cargado y podemos obtener las coordenadas para @@ -277,4 +231,82 @@ namespace CtrEditor.ObjetosSim return 10; } } + + public class VMSimMotor + { + public bool _STATUS_VFD_Ready; + public float STATUS_VFD_ACT_Speed_Hz; + public bool Motor_Running; + public bool STATUS_VFD_Trip; + public bool STATUS_VFD_Warning; + public bool STATUS_VFD_Coasting; + public bool OUT_Run; + public bool OUT_Stop; + public bool OUT_Reversal; + public float OUT_OUT_VFD_REQ_Speed_Hz; + + public void UpdatePLC(PLCModel plc, int NumeroMotor, bool Encendido, int elapsedMilliseconds) + { + var index = 0; + switch (NumeroMotor) + { + case < 100: + index = (int)NumeroMotor - 30 + 300; + break; + } + + OUT_Run = plc.LeerTagBool($"\"DB MotorSimulate\".Motors[{index}].OUT.Run"); + OUT_Reversal = plc.LeerTagBool($"\"DB MotorSimulate\".Motors[{index}].OUT.\"Reversal Direction\""); + OUT_OUT_VFD_REQ_Speed_Hz = (float)plc.LeerTagInt16($"\"DB MotorSimulate\".Motors[{index}].OUT.OUT_VFD_REQ_Speed_Hz"); + + + + if (Encendido) + { + _STATUS_VFD_Ready = true; + Motor_Running = true; + STATUS_VFD_Trip = false; + STATUS_VFD_Warning = false; + STATUS_VFD_Coasting = false; + } + else + { + _STATUS_VFD_Ready = false; + Motor_Running = false; + STATUS_VFD_Trip = true; + STATUS_VFD_Warning = false; + STATUS_VFD_Coasting = false; + } + + plc.EscribirTagBool($"\"DB MotorSimulate\".Motors[{index}].STATUS_VFD_Ready", _STATUS_VFD_Ready); + plc.EscribirTagBool($"\"DB MotorSimulate\".Motors[{index}].Motor_Running", Motor_Running); + plc.EscribirTagBool($"\"DB MotorSimulate\".Motors[{index}].STATUS_VFD_Trip", STATUS_VFD_Trip); + plc.EscribirTagBool($"\"DB MotorSimulate\".Motors[{index}].STATUS_VFD_Warning", STATUS_VFD_Warning); + plc.EscribirTagBool($"\"DB MotorSimulate\".Motors[{index}].STATUS_VFD_Coasting", STATUS_VFD_Coasting); + + plc.EscribirTagInt16($"\"DB MotorSimulate\".Motors[{index}].STATUS_VFD_ACT_Speed_Hz", (int)STATUS_VFD_ACT_Speed_Hz); + + } + + private float CalcSpeedRamp(float MaxRatedHz, float TiempoRampa, float actual, float expected, int elapsedMilliseconds) + { + float hzIncrementsRamp = (MaxRatedHz * 10) / (TiempoRampa * (1000.0f / elapsedMilliseconds)); + float delta = expected - actual; + // Conrtolar si la diferencia no es mayor de lo que falta + if (Math.Abs(hzIncrementsRamp) > Math.Abs(delta)) + hzIncrementsRamp = Math.Abs(delta); + if (delta < 0) + return -hzIncrementsRamp; + else + return hzIncrementsRamp; + } + + public void UpdateSpeed(float MaxRatedHz, float TiempoRampa, int elapsedMilliseconds) + { + // Calculamos la velocidad + STATUS_VFD_ACT_Speed_Hz += CalcSpeedRamp(MaxRatedHz, TiempoRampa, STATUS_VFD_ACT_Speed_Hz, OUT_OUT_VFD_REQ_Speed_Hz, elapsedMilliseconds); + + } + } + } diff --git a/imagenes/filler.png b/imagenes/filler.png new file mode 100644 index 0000000..53f6d7f Binary files /dev/null and b/imagenes/filler.png differ diff --git a/imagenes/motor2.png b/imagenes/motorNegro.png similarity index 100% rename from imagenes/motor2.png rename to imagenes/motorNegro.png diff --git a/imagenes/motorVerde.png b/imagenes/motorVerde.png new file mode 100644 index 0000000..9703d8f Binary files /dev/null and b/imagenes/motorVerde.png differ